﻿/*
* Tea Commerce JavaScript Library
* 
* Version 2.1
* 7. Juli 2011
*
* Copyright:
* Tea Solutions
* www.teasolutions.dk
*
* Developer
* Rune Øllgaard Grønkjær
* rg@teasolutions.dk
*
* Created with jQuery v1.4.2
* Tested with jQuery v1.6
*/
/*
**************************************************
- TEACOMMERCE CLASS
**************************************************
*/
if (typeof TeaCommerce === 'undefined') { var TeaCommerce = {}; }


(function () {

  /*
  **************************************************
  - TEACOMMERCE PUBLIC METHODS
  **************************************************
  */

  TeaCommerce.invokeXSLT = function (xsltFile, nodeId, settings) {
    /// <summary>
    /// Used to run a specific xslt file on the server and then receive the output of the xslt.
    /// To be able to use an xslt like this you must approve it in the Tea Commerce backend.
    /// </summary>
    /// <param name="xsltFile">The name of the xslt file to use as a transform</param>
    /// <param name="nodeId">Id of the product node</param>
    /// <param name="settings">Extra settings for the call (umbracoLanguageId, async, successfn, errorfn, dataType)</param>
    /// <setting name="umbracoLanguageId">Id of the umbraco language.</setting>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <setting name="dataType">The datatype of the return data. 'xml', 'html', 'script', 'json', 'text'</setting>
    /// <returns>Returns the output generated by the xslt</returns>
    settings = tcs.fixSettings(settings);
    return tcs.callBase('InvokeXSLT', [xsltFile, nodeId, settings.umbracoLanguageId], null, settings.async, settings.successfn, settings.errorfn, 'html');
  };

  TeaCommerce.hasOrder = function (settings) {
    /// <summary>
    /// Indication if current user has an order. Always called syncronously.
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>Json bool object</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('HasOrder', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.hasFinalizedOrder = function (settings) {
    /// <summary>
    /// Indication if current user has a finalized order. Always called syncronously.
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>Json bool object</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('HasFinalizedOrder', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.getOrder = function (settings) {
    /// <summary>
    /// Gets the current order from the server
    /// The request is made with a syncronous ajax call
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An order as a Json object</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('GetOrder', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.getFinalizedOrder = function (settings) {
    /// <summary>
    /// Generates a Json string representing the current finalized order
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>The Json serialized order</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('GetFinalizedOrder', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.removeOrder = function (settings) {
    /// <summary>
    /// Removes the current order from the customers session
    /// </summary>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderRemoved Json object</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'removeOrder', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('RemoveOrder', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.setOrderUmbracoLanguage = function (umbracoLanguageId, settings) {
    /// <summary>
    /// Sets the order umbraco language.
    /// </summary>
    /// <param name="umbracoLanguageId">Id of the umbraco language.</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>The affected order Json object</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [umbracoLanguageId],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'setOrderUmbracoLanguage', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('SetOrderUmbracoLanguage', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.addOrderLine = function (nodeId, quantity, settings) {
    /// <summary>
    /// Adds an orderline to the current order.
    /// If the product is already present in the order, the quantity will be added to the orderline
    /// If async is set to false addOrderLine will return the newly added orderLine
    /// </summary>
    /// <param name="nodeId">Id of the product node</param>
    /// <param name="quantity">Number of products to add</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn, properties)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <setting name="properties">Ekstra orderline properties. These will be added alongside the secure properties from the product node, but cannot overwrite the them.</setting>
    /// <returns>An OrderlinesUpdated Json object containing the affected orderLine</setting>
    settings = tcs.fixSettings(settings);
    var parameters = [nodeId, quantity],
        formData = settings.properties;
    tcs.fireCartUpdating({ 'Caller': 'addOrderLine', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('AddOrderLine', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.addUniqueOrderLine = function (nodeId, orderLineId, quantity, settings) {
    /// <summary>
    /// Adds or updates an unique orderline on the current order.
    /// If only a nodeId is provided a new orderline will be created.
    /// If an orderLineId is provided, the quantity will be added to the existing orderline
    /// </summary>
    /// <param name="nodeId">Id of the product node</param>
    /// <param name="orderLineId">Id of the orderline, if -1 a new orderline is added</param>
    /// <param name="quantity">Number of products to add</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn, properties)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <setting name="properties">Ekstra orderline properties. These will be added alongside the secure properties from the product node, but cannot overwrite the them.</setting>
    /// <returns>An OrderlinesUpdated Json object containing the affected orderLines</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [nodeId, orderLineId ? orderLineId : -1, quantity],
        formData = settings.properties;
    tcs.fireCartUpdating({ 'Caller': 'addUniqueOrderLine', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('AddUniqueOrderLine', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.addOrderLineBulk = function (productList, settings) {
    /// <summary>
    /// Adds or updates an array of orderlines to the current order.
    /// If the products is already present in the order, the quantity will be added to the orderline
    /// </summary>
    /// <param name="productList">An object containing the products to add. The keys is the nodeName and the value the quantity</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderlinesUpdated Json object containing the affected orderLines</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = productList;
    tcs.fireCartUpdating({ 'Caller': 'addOrderLineBulk', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('AddOrderLineBulk', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.overwriteQuantity = function (nodeId, quantity, settings) {
    /// <summary>
    /// Overwrites quantity of a specific orderline to the current order.
    /// If the product is not allready present on the order the product will be added
    /// </summary>
    /// <param name="nodeId">Id of the product node</param>
    /// <param name="quantity">Number of products to add</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn, properties)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <setting name="properties">Ekstra orderline properties. These will be added alongside the secure properties from the product node, but cannot overwrite the them.</setting>
    /// <returns>An OrderlinesUpdated Json object containing the affected orderLine</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [nodeId, quantity],
        formData = settings.properties;
    tcs.fireCartUpdating({ 'Caller': 'overwriteQuantity', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('OverwriteQuantity', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.overwriteUniqueQuantity = function (nodeId, orderLineId, quantity, settings) {
    /// <summary>
    /// Overwrites quantity of a specific, unique orderline to the current order.
    /// If the product is not allready present on the order the product will be added
    /// </summary>
    /// <param name="nodeId">Id of the product node</param>
    /// <param name="orderLineId">Id of the orderline, if -1 a new orderline is added</param>
    /// <param name="quantity">Number of products to add</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn, properties)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <setting name="properties">Ekstra orderline properties. These will be added alongside the secure properties from the product node, but cannot overwrite the them.</setting>
    /// <returns>An OrderlinesUpdated Json object containing the affected orderLines</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [nodeId, orderLineId ? orderLineId : -1, quantity],
        formData = settings.properties;
    tcs.fireCartUpdating({ 'Caller': 'overwriteUniqueQuantity', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('OverwriteUniqueQuantity', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.overwriteQuantityBulk = function (productList, settings) {
    /// <summary>
    /// Overwrites a list of orderline quantities
    /// Pass the orderlines along in "form" format where Key: nodeId and Value: new quantity
    /// </summary>
    /// <param name="productList">An object containing the products to add. The keys is the nodeName and the value the quantity</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderlinesUpdated Json object containing the affected orderLines</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = productList;
    tcs.fireCartUpdating({ 'Caller': 'overwriteQuantityBulk', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('OverwriteQuantityBulk', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.updateOrderLineProperty = function (nodeId, propertyAlias, propertyValue, settings) {
    /// <summary>
    /// Updates one information property of the order line
    /// </summary>
    /// <param name="nodeId">The id of the product node</param>
    /// <param name="propertyAlias">The alias of the property to update</param>
    /// <param name="propertyValue">The new value of the property</param>
    /// <param name="settings">Extra settings for the call (umbracoLanguageId, async, successfn, errorfn)</param>
    /// <setting name="umbracoLanguageId">Optional umbraco language id. Send null og 0 if no language is needed</setting>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderLinePropertiesUpdated Json object containing the affected order line properties</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [nodeId, propertyAlias, propertyValue, settings.umbracoLanguageId],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'updateOrderLineProperty', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('UpdateOrderLineProperty', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.updateUniqueOrderLineProperty = function (orderLineId, propertyAlias, propertyValue, settings) {
    /// <summary>
    /// Updates one information property of the unique order line
    /// </summary>
    /// <param name="orderLineId">Id of the orderline, if the orderline is not found an exception is thrown</param>
    /// <param name="alias">The alias of the property to update</param>
    /// <param name="value">The new value of the property</param>
    /// <param name="settings">Extra settings for the call (umbracoLanguageId, async, successfn, errorfn)</param>
    /// <setting name="umbracoLanguageId">Optional umbraco language id. Send null og 0 if no language is needed</setting>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderLinePropertiesUpdated Json object containing the affected order line properties</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [orderLineId ? orderLineId : -1, propertyAlias, propertyValue, settings.umbracoLanguageId],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'updateUniqueOrderLineProperty', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('UpdateUniqueOrderLineProperty', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };
  
  TeaCommerce.updateOrderLineProperties = function (nodeId, propertyList, settings) {
    /// <summary>
    /// Updates a list of properties on the order line
    /// Pass the list of properties along in "form" format where Key: property alias and Value: property value
    /// </summary>
    /// <param name="propertyList">A javascript object with alle the properties to update</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <param name="umbracoLanguageId">Optional umbraco language id. Send null og 0 if no language is needed</param>
    /// <param name="async">Set to false if the call should be syncronous</param>
    /// <param name="successfn">function to call when the command has been completet</param>
    /// <param name="errorfn">function to call if the command has failed</param>
    /// <returns>An OrderLinePropertiesUpdated Json object containing the affected order line properties</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [nodeId, settings.umbracoLanguageId],
        formData = propertyList;
    tcs.fireCartUpdating({ 'Caller': 'updateOrderLineProperties', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('UpdateOrderLineProperties', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.updateUniqueOrderLineProperties = function (orderLineId, propertyList, settings) {
    /// <summary>
    /// Updates the extra information of the unique order line
    /// Pass the extra information along in form format where Key: property alias and Value: property value
    /// </summary>
    /// <param name="orderLineId">Id of the orderline, if the orderline is not found an exception is thrown</param>
    /// <param name="propertyList">A javascript object with alle the properties to update</param>
    /// <param name="settings">Extra settings for the call (umbracoLanguageId, async, successfn, errorfn)</param>
    /// <setting name="umbracoLanguageId">Optional umbraco language id. Send null og 0 if no language is needed</setting>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderLinePropertiesUpdated Json object containing the affected order line properties</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [orderLineId ? orderLineId : -1, settings.umbracoLanguageId],
        formData = propertyList;
    tcs.fireCartUpdating({ 'Caller': 'updateUniqueOrderLineProperties', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('UpdateUniqueOrderLineProperties', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };
  
  TeaCommerce.removeOrderLine = function (nodeId, settings) {
    /// <summary>
    /// Removes an orderline from the current order.
    /// </summary>
    /// <setting name="nodeId">Id of the product node</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderLinesUpdated Json object containing the affected orderLines</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [nodeId],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'removeOrderLine', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('RemoveOrderLine', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.removeUniqueOrderLine = function (orderLineId, settings) {
    /// <summary>
    /// Removes an orderline from the current order
    /// </summary>
    /// <param name="orderLineId">The order line id, if the orderline is not found an exception is thrown.</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderLinesUpdated Json object containing the affected order lines</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [orderLineId ? orderLineId : -1],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'removeUniqueOrderLine', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('RemoveUniqueOrderLine', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };
  
  TeaCommerce.removeAllOrderLines = function (settings) {
    /// <summary>
    /// Removes all orderlines from the current order
    /// </summary>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderlinesUpdated Json object containing the affected orderLines</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'removeAllOrderLines', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('RemoveAllOrderLines', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.updateOrderProperty = function (propertyAlias, propertyValue, settings) {
    /// <summary>
    /// Updates one information property of the order
    /// </summary>
    /// <param name="propertyAlias">The alias of the property to update</param>
    /// <param name="propertyValue">The new value of the property</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderPropertiesUpdated Json object containing the affected orderProperties</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [propertyAlias, propertyValue],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'updateOrderProperty', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('UpdateOrderProperty', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.updateOrderProperties = function (propertyList, settings) {
    /// <summary>
    /// Updates a list of properties on the order
    /// Pass the list of properties along in "form" format where Key: nodeId and Value: new quantity
    /// </summary>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = propertyList;
    tcs.fireCartUpdating({ 'Caller': 'updateOrderProperties', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('UpdateOrderProperties', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.updateOrderPropertyAdmin = function (orderId, propertyAlias, propertyValue, settings) {
    /// <summary>
    /// Updates one information property of a specific order
    /// </summary>
    /// <param name="orderId">The orderId of the order to update</param>
    /// <param name="alias">The alias of the property to update</param>
    /// <param name="value">The new value of the property</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderPropertiesUpdated Json object containing the affected orderProperties</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [orderId, propertyAlias, propertyValue],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'updateOrderPropertyAdmin', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('UpdateOrderPropertyAdmin', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.updateOrderPropertiesAdmin = function (orderId, propertyList, settings) {
    /// <summary>
    /// Updates one information property of a specific order
    /// Pass the extra information along in form format where Key: property alias and Value: property value
    /// </summary>
    /// <param name="orderId">The orderId of the order to update</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>An OrderPropertiesUpdated Json object containing the affected orderProperties</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [orderId],
        formData = propertyList;
    tcs.fireCartUpdating({ 'Caller': 'updateOrderPropertiesAdmin', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('UpdateOrderPropertiesAdmin', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.getStock = function (nodeId, settings) {
    /// <summary>
    /// Fetches the stock of a specific node id
    /// </summary>
    /// <param name="nodeId">The product node</param>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>The stock of the product. Returns null if there is no stock count to the product or if the product does not exist</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [nodeId],
        formData = null;
    return tcs.callBase('GetStock', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.getCurrentCountry = function (settings) {
    /// <summary>
    /// Gets the current country
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>Current country as Json</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('GetCurrentCountry', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.getCountries = function (settings) {
    /// <summary>
    /// Gets all available countries
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>All available countries as Json</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('GetCountries', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.setCurrentCountry = function (id, settings) {
    /// <summary>
    /// Sets the current country
    /// </summary>
    /// <param name="id">Id of the new current country</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>The new current country as Json</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [id],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'setCurrentCountry', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('SetCurrentCountry', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.getCurrentCurrency = function (settings) {
    /// <summary>
    /// Gets the current currency
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>Current currency as Json</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('GetCurrentCurrency', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.getCurrencies = function (settings) {
    /// <summary>
    /// Gets all available currencies
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>All available currencies as Json</returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('GetCurrencies', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.setCurrentCurrency = function (id, settings) {
    /// <summary>
    /// Sets the current currency
    /// </summary>
    /// <param name="id">Id of the new current currency</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>The new current currency as Json</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [id],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'setCurrentCurrency', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('SetCurrentCurrency', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.getShippingMethods = function (settings) {
    /// <summary>
    /// Gets all available shipping methods filtered by the current country
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>All available shipping methods </returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('GetShippingMethods', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.setShippingMethod = function (id, settings) {
    /// <summary>
    /// Sets the shippingmethod of the order
    /// </summary>
    /// <param name="id">Id of the shippingmethod</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>The new shippingmethod.</returns>
    settings = tcs.fixSettings(settings);
    var parameters = [id],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'setShippingMethod', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('SetShippingMethod', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.getPaymentMethods = function (settings) {
    /// <summary>
    /// Gets all available payment methods filtered by the current country
    /// </summary>
    /// <param name="settings">Extra settings for the call (errorfn)</param>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>All available payment methods </returns>
    settings = tcs.fixSettings(settings);
    var parameters = null,
        formData = null;
    return tcs.callBase('GetPaymentMethods', parameters, formData, false, null, settings.errorfn);
  };

  TeaCommerce.setPaymentMethod = function (id, settings) {
    /// <summary>
    /// Sets the paymentmethod of the order
    /// </summary>
    /// <param name="id">Id of the paymentmethod</param>
    /// <param name="settings">Extra settings for the call (async, successfn, errorfn)</param>
    /// <setting name="async">Set to false if the call should be syncronous</setting>
    /// <setting name="successfn">function to call when the command has been completet</setting>
    /// <setting name="errorfn">function to call if the command has failed</setting>
    /// <returns>The new paymentmethod. </returns>
    settings = tcs.fixSettings(settings);
    var parameters = [id],
        formData = null;
    tcs.fireCartUpdating({ 'Caller': 'setPaymentMethod', 'parameters': parameters, 'formData': formData });
    return tcs.callBase('SetPaymentMethod', parameters, formData, settings.async, function (data) {
      tcs.fireCartUpdated(data, settings.successfn);
    }, function (data) {
      tcs.fireCartUpdateError(data, settings.errorfn);
    });
  };

  TeaCommerce.goToPayment = function () {
    /// <summary>
    /// Fetches the chosen payment method from the server and sends the user to payment OR
    /// if no payment is necesary the order will be finalized and the user sent to the 
    /// confirmation page. For this to work the order MUST have a payment method attached.
    /// </summary>
    var parameters = null,
        formData = null;
    var rtnData = tcs.callBase('GeneratePaymentForm', parameters, formData, false, null, null);

    var form = jQuery(rtnData.form);
    jQuery('body').append(form);
    if(rtnData.submitJavascriptFunction){
      eval (rtnData.submitJavascriptFunction);
    } else {
      form[0].submit();
    }
  };

  /*
  **************************************************
  - TEACOMMERCE EVENT HANDLERS
  **************************************************
  */

  TeaCommerce.subscribeToOnCartUpdated = function (method) {
    /// <summary>
    /// Subscribes a method to the onCartUpdated event
    /// </summary>
    /// <param name="method">The method to fire</param>
    tcs.onCartUpdated(method);
  };

  TeaCommerce.subscribeToOnCartUpdating = function (method) {
    /// <summary>
    /// Subscribes a method to the onCartUpdating event
    /// </summary>
    /// <param name="method">The method to fire</param>
    tcs.onCartUpdating(method);
  };

  TeaCommerce.subscribeToOnCartUpdateError = function (method) {
    /// <summary>
    /// Subscribes a method to the onCartUpdateError event
    /// </summary>
    /// <param name="method">The method to fire</param>
    tcs.onCartUpdateError(method);
  };

  /*
  **************************************************
  - TEACOMMERCE UTILS
  **************************************************
  */

  TeaCommerce.parseJsonDate = function (date) {
    /// <summary>
    /// Parses a Json date to a Date object
    /// </summary>
    /// <param name="date">The date string to parse</param>
    /// <returns>A Date object</returns>
    if (date && date.indexOf("/Date(") === -1) {
      return date;
    }
    return new Date(parseInt(date.substr(6), 10));
  };

  /*
  **************************************************
  - TEACOMMERCE PRIVATE SERVICE OBJECT
  **************************************************
  */

  var TeaCommerceService = function () {
    var teaCommerceService = this;
    teaCommerceService.cartUpdatedSubscribers = [];
    teaCommerceService.cartUpdateErrorSubscribers = [];
    teaCommerceService.cartUpdatingSubscribers = [];
    teaCommerceService.errorMessages = {teacommerceerror001: 'Tea Commerce is not licensed\nYou can only have 20 orders in the test version.\nDelete some orders and you are up and running again.\n\nBuy a license at http://www.teacommerce.dk'};
    teaCommerceService.callBase = function (methodName, args, data, async, successfn, errorfn, dataType) {
      /// <summary>
      /// Makes an ajax call to the TeaCommerce base
      /// Standard is an asyncronous call
      /// </summary>
      /// <param name="methodName">Name of the base method to call</param>
      /// <param name="args">The args to send to the base method in the correct order</param>
      /// <param name="data">Dataobject to send to the server. If this is an {} object it will be passed as POST data. If data is a string they will be sent as QueryString parameters</param>
      /// <param name="successfn">function to call when the command has been completet</param>
      /// <param name="errorfn">function to call if the command has failed</param>
      /// <param name="async">Set to false if the call should be syncronous</param>
      /// <returns>The return data from the server IF async = false</returns>
      var rtnData = null;
      if (typeof async === 'undefined') {
        async = true;
      }
      if (typeof dataType === 'undefined') {
        dataType = 'json';
      }
      jQuery.ajax({
        type: 'POST',
        url: teaCommerceService.createBaseUrl(methodName, args),
        data: data,
        async: async,
        success: function (data) {
          rtnData = teaCommerceService.fixDates(data);
          if (successfn) {
            successfn(data);
          }
        },
        error: function(data) {
          if(data.responseText.indexOf('teacommerceerror001') > -1){
            alert(teaCommerceService.errorMessages.teacommerceerror001);
          }
          if(errorfn){
            errorfn(data);
          }
        },
        cache: false,
        contentType: 'application/x-www-form-urlencoded; charset=utf-8',
        dataType: dataType
      });
      return rtnData;
    };

    teaCommerceService.fixDates = function (jsonOrder) {
      /// <summary>
      /// Fixes the three dates on an order Json object. (CreatedDate, ModifiedDate and OrderDate)
      /// </summary>
      /// <param name="jsonOrder">The Json order</param>
      if (jsonOrder) {
        if (jsonOrder.CreatedDate) {
          jsonOrder.CreatedDate = TeaCommerce.parseJsonDate(jsonOrder.CreatedDate);
        }
        if (jsonOrder.ModifiedDate) {
          jsonOrder.ModifiedDate = TeaCommerce.parseJsonDate(jsonOrder.ModifiedDate);
        }
        if (jsonOrder.OrderDate) {
          jsonOrder.OrderDate = TeaCommerce.parseJsonDate(jsonOrder.OrderDate);
        }
      }
      return jsonOrder;
    };

    teaCommerceService.createBaseUrl = function (method, args) {
      /// <summary>
      /// Creates an url to call a method on the TeaCommerce base.
      /// </summary>
      /// <param name="methodName">Name of the base method to call</param>
      /// <param name="args">The args to send to the base method in the correct order</param>
      var baseUrl = '/tcbase/teacommerce/' + method;
      if (args) {
        for ( i = 0; i < args.length; i++) {
          baseUrl += '/' + args[i];
        }
      }
      return baseUrl + '.aspx';
    };

    teaCommerceService.fixSettings = function (settings) {
      /// <summary>
      /// Fixes the settings
      /// </summary>
      /// <param name="methodName">The method to call</param>
      var defaultSettings = {
        umbracoLanguageId: 0
      };
      return jQuery.extend(defaultSettings, settings);
    };

    teaCommerceService.onCartUpdated = function (method) {
      /// <summary>
      /// Subscribes a method to the onCartUpdated event
      /// </summary>
      /// <param name="methodName">The method to call</param>
      teaCommerceService.cartUpdatedSubscribers.push(method);
    };

    teaCommerceService.fireCartUpdated = function (data, extraMethod) {
      /// <summary>
      /// Fires the onCartUpdated event
      /// </summary>
      /// <param name="data">The data of the update</param>
      if (extraMethod) {
        extraMethod(data);
      }
      for ( i = 0; i < teaCommerceService.cartUpdatedSubscribers.length; i++) {
        teaCommerceService.cartUpdatedSubscribers[i](data);
      }
    };

    teaCommerceService.onCartUpdating = function (method) {
      /// <summary>
      /// Subscribes a method to the onCartUpdating event
      /// </summary>
      /// <param name="methodName">The method to call</param>
      teaCommerceService.cartUpdatingSubscribers.push(method);
    };

    teaCommerceService.fireCartUpdating = function (data) {
      /// <summary>
      /// Fires the onCartUpdating event
      /// </summary>
      /// <param name="data">The data of the update</param>
      for ( i = 0; i < teaCommerceService.cartUpdatingSubscribers.length; i++) {
        teaCommerceService.cartUpdatingSubscribers[i](data);
      }
    };

    teaCommerceService.onCartUpdateError = function (method) {
      /// <summary>
      /// Subscribes a method to the onCartUpdateError event
      /// </summary>
      /// <param name="extraMethod">An extra method to call</param>
      teaCommerceService.cartUpdateErrorSubscribers.push(method);
    };

    teaCommerceService.fireCartUpdateError = function (data, extraMethod) {
      /// <summary>
      /// Fires the onCartUpdateError event
      /// </summary>
      /// <param name="data">The data of the update error</param>
      /// <param name="extraMethod">An extra method to call</param>
      if (extraMethod) {
        extraMethod(data);
      }
      for ( i = 0; i < teaCommerceService.cartUpdateErrorSubscribers.length; i++) {
        teaCommerceService.cartUpdateErrorSubscribers[i](data);
      }
    };
  };
  var tcs = new TeaCommerceService();

})();
