ko.bindingHandlers.uiTabs = {
    init: function (el) {
        $(el).tabs();
    }
};

ko.observableArray.fn.sortByProperty = function (prop) {
    this.sort(function (o1, o2) {
        /*
        if (o1[prop] == o2[prop]) { return 0; }
        if (o1[prop] < o2[prop]) { return -1; }
        return 1;
        */
        return -1;
    });
};

Date.prototype.toMSJSON = function () {
    var date = '/Date(' + this.getTime() + ')/';
    return date;
};

var ko__pathToRoot = "";




var vm = vm || {};
vm.initialize = function () {

    var cart = new koCart({});
    var cartInfo = cart.getFromServer();

    var user = new koUser({});
    var userInfo = user.getFromServer();

    vm.cart = ko.observable();
    vm.user = ko.observable();
    vm.checkout = ko.observable();

    vm.cardIssuers = [ 'MasterCard','Visa' ];
    vm.cardYears = [ "2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021" ];

    cartInfo.done(function (data) { $(".CartAndOptions").show(); showServerObjectNotes(data); });
    userInfo.done(function (data) { $(".UserSpot").show();       showServerObjectNotes(data); });

    $.when(cartInfo, userInfo).done(function (cartData, userData) {
        vm.cart(new koCart(cartData[0]));
        vm.user(new koUser(userData[0]));
        //console.log('cartData = ', cartData[0]);
        vm.checkout(new koCheckout(cartData[0].Checkout, vm.user));

        //console.log('initializing vm applyBindings...');

        ko.applyBindings(vm);

        $(".profile-dialog").show();

    });

}

$(document).ready(function () {
    //console.log('initializing vm ...');
    vm.initialize();
});


/********************************
  PUBSUB pipes
********************************/

var pubkey_CartData = "cart/data";
var pubkey_CartNameChanged = "cart/nameChanged";

pubsub.subscribe(pubkey_CartData, function (data) {
    vm.cart(new koCart(data));
    //console.log('listened to ' + pubkey_CartData);
    showServerObjectNotes(data);
});
pubsub.subscribe(pubkey_CartNameChanged, function (data) {
    if (data.cssClass == "ok") {
        noty({ type: "information", text: data.message });
        $(".kartName").text($("#input-cartName").val());
        $("#dialog-setCartName").dialog("close");
        
    } else {
        noty({ type: "error", text: data.message });
    }
});




// ajaxcall wrap
var ajaxHelper = {};
ajaxHelper.request = function (settings) {
    var noteid = settings.id || '';
    if (settings.waitingText) {
        var usermsg = "<span class='working'></span> " + settings.waitingText;
        noty({ text: usermsg, id: noteid });
    }
    var prom = $.ajax({
            url: settings.url,
            type: settings.type,
            timeout: settings.timeout || 25000,
            contentType: settings.contentType || "application/json; charset=utf-8",
            dataType: settings.dataType || "json",
            data: settings.data || '',
            ctx: settings.ctx || {}
        }).done(function () {
            $.noty.close(noteid);
        }).fail(function (jqXHR, textStatus, errObj) {
            if (textStatus == "timeout") {
                noty({ type: "error", text: "Server [ajax] request timed out." });
                $.noty.close(noteid);
            }
        });
    return prom;
};





// polyfills

if ('function' !== typeof Array.prototype.reduce) {
  Array.prototype.reduce = function(callback, opt_initialValue){
    'use strict';
    if (null === this || 'undefined' === typeof this) {
      // At the moment all modern browsers, that support strict mode, have
      // native implementation of Array.prototype.reduce. For instance, IE8
      // does not support strict mode, so this check is actually useless.
      throw new TypeError(
          'Array.prototype.reduce called on null or undefined');
    }
    if ('function' !== typeof callback) {
      throw new TypeError(callback + ' is not a function');
    }
    var index, value,
        length = this.length >>> 0,
        isValueSet = false;
    if (1 < arguments.length) {
      value = opt_initialValue;
      isValueSet = true;
    }
    for (index = 0; length > index; ++index) {
      if (this.hasOwnProperty(index)) {
        if (isValueSet) {
          value = callback(value, this[index], index, this);
        }
        else {
          value = this[index];
          isValueSet = true;
        }
      }
    }
    if (!isValueSet) {
      throw new TypeError('Reduce of empty array with no initial value');
    }
    return value;
  };
}