﻿/*
* Purpose: This widget is to display the date-picker for a specific trip. The trip data is passed in the form of JSON.
*          The minDate, maxDate for the date picker will be the trip-begin and end date respectively.
*
* Author:  Ubayeed Syed, ubayeed@gmail.com
* Date  :  10th Nov 2010
*/

(function ($) {

    $.widget("ui.tripDatePicker", {

        options: {
            jsonTripRawText: null,
            defaultTooltip: "Your day in [CITY]",   //Default tooltip. [CITY] is 
            flgShowDateTooltip: false,              //indicates if pretty date needs to be shown on tooltip. If true will override the default tooltip value and show the date in the format "mmm dd yyyy"
            flgShowAirportCode: true,               //if True we will show 3letter airport code on the date tooltip. If False will show the City name.
            flgIsMobileView: false,                 //Indicates if the current view is for Mobile phones. By default this is the Trip-View.
            flgIsMobileListView: false,             //Indicates if the current Mobile view on Mobile phones is List View.
            flgIsEntireCalendarReadyonly: false,    //Indicates if the current calendar is all read-only (facebook, twitter)
            flgAutoSelectDate: false,               //Indicates if the Date picker should auto-select a date on load.
            defaultSelectDateOnLoad: null,          //If "flgAutoSelectDate=true" Selects this date on load. 
            dateFormat: "mmm dd yyyy",
            tripCalendarElement: null,
            loadingElement: null,
            tripDaysLoadingElement: null,           //This is the loading element of the tripDays - when html() is updated on Calendar save().
            eventEditContainerID: "eventEditContainerID", //ID of the DIV that shows the Event container.
            tripDaysContentID: "contentTripDays",
            eventOnCloseDialog: function () { },
            eventOnDateSelect: function (date, jsonTrip, element) { }
        },

        _updateEventsJSONData: function () {
            var self = this;
            if (self.options.tripCalendarElement != null) {
                self.options.tripCalendarElement.tripCalendar('updateEventsJSONData');
            }
        },

        pushEventChangesToDB: function (flgRefreshTrip) {
            var self = this;

            self.element.data("flgRefreshTripOnUpdates", flgRefreshTrip);

            self._updateEventsJSONData();
            //Update1: Delete the existing events from DB.
            self._deleteEventsFromDB();
            //Update2: Update the existing events in the DB.
            self._updateEventsToDB();
            //Update3: Add new events to the DB.
            self._insertNewEventsToDB();
        },

        getTotalEventChangesToDB: function () {
            var iTotalEvents = 0;
            var self = this;

            iTotalEvents = self.element.data("calEventsToUpdate").length;
            iTotalEvents += self.element.data("calEventsNewToInsert").length;
            iTotalEvents += self.element.data("calEventsToDelete").length;

            return iTotalEvents;
        },

        updateWCTitleMsg: function () {
            var iTotalEvents = 0;
            var self = this;

            iTotalEvents = self.element.data("calEventsToUpdate").length;
            iTotalEvents += self.element.data("calEventsNewToInsert").length;
            iTotalEvents += self.element.data("calEventsToDelete").length;

            if (iTotalEvents > 0) {
                var txt = '';
                var $msgElement = null;
                $.each($.find('.wc-title-msg'), function (iCounter, element) {
                    $(this).show();
                    $msgElement = $(this);
                    txt = $(this).text();
                    return false;
                });
                if (txt.match(/\[EVENTS\]|\d+/)) {
                    $msgElement.html(txt.replace(/\[EVENTS\]|\d+/, iTotalEvents));
                } else if (txt.match()) {
                }
            }
            else {
                $.each($.find('.wc-title-msg'), function (iCounter, element) {
                    $(this).hide();
                    return false;
                });
            }
        },

        _refreshTrip: function () {
            var iTotalEvents = 0;
            var self = this;

            if (self.element.data("flgRefreshTripOnUpdates") == true) {
                //Make sure to refresh only when we know that all the DB updates are done.
                if (self.element.data("flgRefreshTripOnEventsDelete") == true &&
                    self.element.data("flgRefreshTripOnEventsUpdate") == true &&
                    self.element.data("flgRefreshTripOnEventsInsert") == true) {

                    var iTripID = self.options.tripCalendarElement.tripCalendar('getOptions').jsonTrip.iTripID;

                    self.options.tripCalendarElement.tripCalendar('showLoading');

                    //Save it to the DB.
                    $.post("/Search/GetTrip",
                        { "iTripID": iTripID },
                        function (data) {
                            self._onSuccessRefreshTrip(data);
                        },
                        "json");
                }
            }
            else {
                trace("refresh trip did not happen!");
            }

        },

        _onSuccessRefreshTrip: function (dataJsonTrip) {
            var self = this;
            //alert('refresh onsucces entered');
            if (dataJsonTrip != null) {
                self.options.jsonTripRawText = JSON.stringify(dataJsonTrip);
                self.options.tripCalendarElement.tripCalendar('refreshTrip', dataJsonTrip);
                self._init();
                self.updateWCTitleMsg();
                self._updateTripDaysModel(dataJsonTrip.iTripID);
            }
            //self.options.tripCalendarElement.tripCalendar('hideLoading');
        },

        _updateTripDaysModel: function (tripID) {
            var self = this;

            if (tripID != undefined && tripID != null && tripID > 0) {
                var params = { id: tripID };

                if (self.options.tripDaysLoadingElement != null) {
                    self.options.tripDaysLoadingElement.show();
                }

                $.post("/Trip/Details",
                        params,
                        function (html) {
                            if ($.browser.msie) {
                                $('#' + self.options.tripDaysContentID).empty();
                                $('#' + self.options.tripDaysContentID).append(html);
                            }
                            else {
                                $('#' + self.options.tripDaysContentID).html(html);
                            }
                            $.getScript('../../Scripts/onPageLoad.js',
                                        function () {
                                            /*alert('datepicker - loaded and executed')*/
                                            if (self.options.tripDaysLoadingElement != null) {
                                                self.options.tripDaysLoadingElement.hide();
                                            }
                                        }
                                        );
                            self.options.tripCalendarElement.tripCalendar('hideLoading');
                        },
                        "html");
            }
            self.options.eventOnCloseDialog();
        },

        _updateEventsToDB: function () {
            var self = this;

            //Loop in each Event to be Updated
            if (self.element.data("calEventsToUpdate").length > 0) {
                var jsonPlans = JSON.stringify(self.element.data("calEventsToUpdateJSON"));
                var iTripID = self.options.tripCalendarElement.tripCalendar('getOptions').jsonTrip.iTripID;
                //Save it to the DB.
                self.element.data("flgRefreshTripOnEventsUpdate", false);
                //                $.post("/Search/UpdatePhoneProfile",
                //                    { "iTripID": iTripID, "sJsonPlans": jsonPlans },
                ////                    function (data) {
                ////                        self._onSuccessUpdateTripPlans(data, self);
                ////                    },
                //                    "json");
                $.post("/Search/InsertOrUpdateTripPlans",
                    { "iTripID": iTripID, "sJsonPlans": jsonPlans },
                    function (data) {
                        self._onSuccessUpdateTripPlans(data, self);
                    },
                    "json");
            }
        },

        _onSuccessUpdateTripPlans: function (data, self) {
            /*
            * UBS 11/25/2010: This is callback function for "/Search/InsertOrUpdateTripPlan". 
            * History : 
            * 1) UBS 11/25/2010 8am - Since I am trying to do all updates from TripCalendar.ascx:Save() this function may
            * have to be moved or decommissioned.
            */
            var options = self.options;
            if (data.flgResult == true) {
                self.element.data("flgRefreshTripOnEventsUpdate", true);
                $.each(self.element.data("calEventsToUpdate"), function (i, calEvent) {
                    self.element.weekCalendar("updateEvent", calEvent);
                });
                self._refreshTrip();
            }
            else {
                //Could not save to the DB therefore do not close instead show the error msg.
                //self._displayServerError($("#" + options.eventEditContainerID), calEvent);
            }
        },

        _insertNewEventsToDB: function () {
            var self = this;
            //Loop in each Event to be Updated
            if (self.element.data("calEventsNewToInsertJSON").length > 0) {
                var jsonPlans = JSON.stringify(self.element.data("calEventsNewToInsertJSON"));
                var iTripID = self.options.tripCalendarElement.tripCalendar('getOptions').jsonTrip.iTripID;
                //Save it to the DB.
                self.element.data("flgRefreshTripOnEventsInsert", false);
                //                $.post("/Search/UpdatePhoneProfile",
                //                //{ "iTripID": iTripID, "sJsonPlans": {JsonPlans: jsonPlans} },
                //                    {"iTripID": iTripID, "sJsonPlans": jsonPlans },
                //                //                    function (data) {
                //                //                        self._onSuccessInsertNewTripPlans(data, self);
                //                //                    },
                //                    "json");
                $.post("/Search/InsertOrUpdateTripPlans",
                //{ "iTripID": iTripID, "sJsonPlans": {JsonPlans: jsonPlans} },
                    {"iTripID": iTripID, "sJsonPlans": jsonPlans },
                    function (data) {
                        self._onSuccessInsertNewTripPlans(data, self);
                    },
                    "json");
            }
        },

        /*
        * UBS 11/25/2010: This is callback function for "/Search/InsertOrUpdateTripPlans". 
        * History : 
        * 1) UBS 11/25/2010 8am - Since I am trying to do all updates from TripCalendar.ascx:Save() this function may
        * have to be moved or decommissioned.
        */
        _onSuccessInsertNewTripPlans: function (data, self) {
            var options = self.options;
            if (data.flgResult == true) {
                self.element.data("flgRefreshTripOnEventsInsert", true);
                self.element.weekCalendar("removeUnsavedEvents");
                self._refreshTrip();
            }
            else {
                //Show the error warnings and hide the required indicators.
                //TODO - figure out how to handle the errors.
            }
        },

        _deleteEventsFromDB: function () {
            var self = this;
            //Loop in each Event to be Updated
            if (self.element.data("calEventsToDelete").length > 0) {
                var jsonPlans = JSON.stringify(self.element.data("calEventsToDeleteJSON"));
                var iTripID = self.options.tripCalendarElement.tripCalendar('getOptions').jsonTrip.iTripID;
                //Save it to the DB.
                self.element.data("flgRefreshTripOnEventsDelete", false); //set to false here, reset it to true in its callback.
                $.post("/Search/DeleteTripPlans",
                    { "iTripID": iTripID, "sJsonPlans": jsonPlans },
                    function (data) {
                        self._onSuccessDeleteTripPlans(data, self);
                    },
                    "json");
            }
        },

        /*
        * UBS 11/25/2010: This is callback function for "/Search/DeleteTripPlans". 
        */
        _onSuccessDeleteTripPlans: function (data, self) {
            if (data.flgResult == true) {
                self.element.data("flgRefreshTripOnEventsDelete", true);
                if (self.element.data("calEventsToDelete").length > 0) {
                    $.each(self.element.data("calEventsToDelete"), function (i, calEvent) {
                        self.element.weekCalendar("removeEvent", calEvent.id);
                    });
                }
                self._refreshTrip();
            }
            else {
                //Could not delete it from DB therefore do not close instead show the error msg.
                //TODO : figure out how to display the error.                
            }
        },

        _create: function () {
            var self = this;
            var options = this.options;
            self._renderDatePicker();
            $("#" + options.eventEditContainerID).hide();
            self._autoSelectDate();
        },

        _init: function () {
            var self = this;
            var options = this.options;
            self._renderDatePicker();
            $("#" + options.eventEditContainerID).hide();
            self._autoSelectDate();
        },

        _autoSelectDate: function () {
            var self = this;
            var options = this.options;
            if (options.flgAutoSelectDate) {
                var date = '';
                if (options.defaultSelectDateOnLoad == null) {
                    date = self.element.data("minDate");
                } else {
                    if (typeof options.defaultSelectDateOnLoad == "string") {
                        try {
                            date = self._dateDeserialize(options.defaultSelectDateOnLoad);
                        } catch (e) {
                            trace("tripDatePicker: _autoSelectDate() defaultSelectDateOnLoad = " + defaultSelectDateOnLoad + " cannot be deserialized");
                            date = new Date(options.defaultSelectDateOnLoad);
                        }
                    }
                    else if (typeof options.defaultSelectDateOnLoad == "object") {
                        date = options.defaultSelectDateOnLoad;
                    }
                }
                var dateText = $.datepicker.formatDate("m/d/yy", date);
                options.eventOnDateSelect(dateText, null, self.element);
            }
        },

        _deserializeJsonTripText: function () {
            var jsonTrip = null;
            var self = this;
            var options = self.options;
            try {
                //jsonTrip = JSON.parse(options.jsonTripRawText.replace(/&amp;#39;/gi, '\'').replace(/&#39;/gi, '').replace(/&amp;quot;/gi, '"').replace(/&quot;/gi, '"'));
                //UBS 12/30/2010: The above was working fine in FF but not in IE and Chrome. Replacing the '\n' with '\\n' so that JSON serializer works fine in IE/Chrome.
                jsonTrip = JSON.parse(options.jsonTripRawText.replace(/&amp;#39;/gi, '\'').replace(/&#39;/gi, '').replace(/&amp;quot;/gi, '"').replace(/&quot;/gi, '"').replace(/\n/gi, "\\n").replace(/\r/gi, "\\r"));
            }
            catch (e) {
                alert(e);
            }
            return jsonTrip;
        },

        _renderDatePicker: function () {
            var options = this.options;
            var self = this;
            var jsonTrip = null;
            var jsonPlan = null;
            var jsonPlans = null;
            var minDate = null;
            var maxDate = null;

            if (options.jsonTripRawText != null) {

                //try {
                //    jsonTrip = JSON.parse(options.jsonTripRawText.replace(/&amp;#39;/gi, '\'').replace(/&#39;/gi, '').replace(/&amp;quot;/gi, '"').replace(/&quot;/gi, '"'));
                //}
                //catch (e) {
                //    //alert(e);
                //}

                jsonTrip = self._deserializeJsonTripText();

                if (options.flgIsMobileView && tripDatePicker_Cache != undefined) {
                    //tripDatePicker_Cache.push(this);
                    //tripDatePicker_Cache.push({ 'iTripId': jsonTrip.iTripID, 'item': this })
                    var flgCacheFound = false;
                    $.each(tripDatePicker_Cache, function (i, dtPicker) {
                        if (dtPicker.iTripId == jsonTrip.iTripID) {
                            dtPicker.item = self;
                            flgCacheFound = true;
                            return false;
                        }
                    });
                    if (!flgCacheFound) {
                        tripDatePicker_Cache.push({ 'iTripId': jsonTrip.iTripID, 'item': self })
                    }
                    if (options.flgIsMobileListView) {
                        self.element.hide();
                    } else {
                        self.element.show();
                    }
                }

                minDate = _dateDeserialize(jsonTrip.BeginDateTime)
                maxDate = _dateDeserialize(jsonTrip.EndDateTime)

                self.element.data("minDate", minDate);
                self.element.data("maxDate", maxDate);
                self.element.data("jsonTrip", jsonTrip);

                self.element.data("calEventsNewToInsert", []);      //Stores the new events that needs to be inserted.
                self.element.data("calEventsNewToInsertJSON", "");  //stores the Json text of the entire new events to be inserted.
                self.element.data("flgRefreshTripOnEventsDelete", true);    //if true indicates that the New events Insertion happened succesfully in the DB.

                self.element.data("calEventsToUpdate", []);         //Stores the old events that needs to be updated.      
                self.element.data("calEventsToUpdateJSON", "");     //stores the Json text of the entire old events to be updated.
                self.element.data("flgRefreshTripOnEventsUpdate", true);    //if true indicates that the Update events happened succesfully in the DB.

                self.element.data("calEventsToDelete", []);         //Stores the old events that needs to be deleted.
                self.element.data("calEventsToDeleteJSON", "");     //stores the Json text of the entire old events to be deleted.
                self.element.data("flgRefreshTripOnEventsInsert", true);    //if true indicates that the Delete events happened succesfully in the DB.

                if (self.options.tripDaysLoadingElement != null) {
                    self.options.tripDaysLoadingElement.hide();
                }

                if (self.options.defaultSelectDateOnLoad != null) {
                    if (typeof self.options.defaultSelectDateOnLoad == "string") {
                        defaultDate = self._dateDeserialize(self.options.defaultSelectDateOnLoad);
                    } else if (typeof self.options.defaultSelectDateOnLoad == "object") {
                        defaultDate = self.options.defaultSelectDateOnLoad;
                    }
                } else {
                    defaultDate = minDate;
                }

                if (jsonTrip.Plans != null) {
                    $.each(jsonTrip.Plans, function (iPlanCounter, jsonPlan) {
                        //form the calendar events.
                    });
                }

                self.element.datepicker({
                    minDate: minDate,
                    maxDate: maxDate,
                    defaultDate: defaultDate,
                    changeMonth: false,
                    hideIfNoPrevNext: true,
                    defaultDate: defaultDate,
                    onSelect: function (dateText, inst) {
                        options.eventOnDateSelect(dateText, inst, self.element);
                    },
                    beforeShow: function () {
                        //Fired only for inline-date pickers.
                    },
                    beforeShowDay: function (date) {
                        var dateString = 'date-' + date.getDate() + '-' + date.getMonth() + '-' + date.getFullYear();
                        if (date >= minDate && date <= maxDate) {
                            var toolTipAndLegNum = self._getTooltipAndLegNum(date, jsonTrip);
                            if (toolTipAndLegNum != null && toolTipAndLegNum.length == 2) {
                                return [true, "tripDate" + toolTipAndLegNum[1], toolTipAndLegNum[0]];
                            }
                        }
                        else {
                            return [true, '', 'tooltip'];
                        }
                    }
                });

            } //end of if - options.jsonTrip
        }, //end of _renderDatePicker()

        _getTooltipAndLegNum: function (date, jsonTrip) {
            var sTooltip = '';
            var iLegNum = null;
            var self = this;
            if (date != undefined && date != null && jsonTrip != null) {
                if (jsonTrip != null) {
                    if (jsonTrip.Legs != null) {
                        $.each(jsonTrip.Legs, function (iLegCounter, oCurrLeg) {
                            if (iLegCounter + 1 < jsonTrip.Legs.length) {
                                var oNextLeg = jsonTrip.Legs[iLegCounter + 1];
                                if (self._isDateInRange(date, self._dateDeserialize(oCurrLeg.EndDateTime), self._dateDeserialize(oNextLeg.BeginDateTime))) {
                                    sTooltip = self._getTooltip(date, oCurrLeg);
                                    iLegNum = iLegCounter;
                                    return false;
                                }
                            }
                            else {
                                //It means its the last leg therefore
                                sTooltip = self._getTooltip(date, oCurrLeg);
                                iLegNum = iLegCounter;
                            }
                        });
                    } else if (jsonTrip.Hotels != null) {
                        //It means its a hotel only or Hotel + Car only trip
                        $.each(jsonTrip.Hotels, function (iHotelCounter, oHotel) {
                            if (self._isDateInRange(date, self._dateDeserialize(oHotel.BeginDateTime), self._dateDeserialize(oHotel.EndDateTime))) {
                                sTooltip = self._getTooltipHotelOnlyTrip(date, oHotel);
                                return false;
                            } else if (self._dateDeserialize(oHotel.EndDateTime).getDate() == date.getDate()) {
                                //even if its the last day of the hotel stay make sure you assign the same tooltip.
                                sTooltip = self._getTooltipHotelOnlyTrip(date, oHotel);
                                return false;
                            }
                        });
                    } else if (jsonTrip.Cars != null) {
                        //It means its a Car only
                        $.each(jsonTrip.Cars, function (iCarCounter, oCar) {
                            if (self._isDateInRange(date, self._dateDeserialize(oCar.BeginDateTime), self._dateDeserialize(oCar.EndDateTime))) {
                                sTooltip = self._getTooltipCarOnlyTrip(date, oCar);
                                return false;
                            } else if (self._dateDeserialize(oCar.EndDateTime).getDate() == date.getDate()) {
                                //even if its the last day of the car rental make sure you assign the same tooltip.
                                sTooltip = self._getTooltipHotelOnlyTrip(date, oCar);
                                return false;
                            }
                        });
                    }
                }
            }
            return [sTooltip, iLegNum];
        }, //end of _getTooltipAndLegNum()

        _getTooltip: function (date, oCurrLeg) {
            /*
            * Author UBS 11/10/2010: Sets the tooltip on calendar date for trips that has Air.
            */
            var self = this;
            var sTooltip = '';
            if (self.options.flgShowDateTooltip) {
                sTooltip = self._dateGet(date, self.options.dateFormat)
            } else {
                if (self.options.flgShowAirportCode) {
                    sTooltip = self.options.defaultTooltip.replace(/\[CITY\]/, oCurrLeg.ToCity);
                }
                else {
                    //TODO: need to get city name because ToCity = Airport code.
                    sTooltip = self.options.defaultTooltip.replace(/\[CITY\]/, oCurrLeg.ToCity);
                }
            }
            return sTooltip;
        },

        _getTooltipHotelOnlyTrip: function (date, oHotel) {
            /*
            * Author UBS 4/6/2011: Sets the tooltip on calendar date for Hotel, Hotel + Car only trips.
            */
            var self = this;
            var sTooltip = '';
            if (self.options.flgShowDateTooltip) {
                sTooltip = self._dateGet(date, self.options.dateFormat)
            } else {
                if (self.options.flgShowAirportCode) {
                    sTooltip = self.options.defaultTooltip.replace(/\[CITY\]/, oHotel.City);
                }
                else {
                    //TODO: need to get city name because ToCity = Airport code.
                    sTooltip = self.options.defaultTooltip.replace(/\[CITY\]/, oHotel.City);
                }
            }
            return sTooltip;
        },

        _getTooltipCarOnlyTrip: function (date, oCar) {
            /*
            * Author UBS 4/6/2011: Sets the tooltip on calendar date for Car only trips.
            */
            var self = this;
            var sTooltip = '';
            if (self.options.flgShowDateTooltip) {
                sTooltip = self._dateGet(date, self.options.dateFormat)
            } else {
                if (self.options.flgShowAirportCode) {
                    sTooltip = self.options.defaultTooltip.replace(/\[CITY\]/, oCar.ToCity);
                }
                else {
                    //TODO: need to get city name because ToCity = Airport code.
                    sTooltip = self.options.defaultTooltip.replace(/\[CITY\]/, oCar.ToCity);
                }
            }
            return sTooltip;
        },

        _isDateInRange: function (date, beginDate, endDate) {
            var flgReturn = false;
            if (date != null && beginDate != null && endDate != null) {
                var normalizeBeginDt = new Date(beginDate.getFullYear(), beginDate.getMonth(), beginDate.getDate(), 0, 0, 0, 0);
                var normalizeEndDt = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate(), 0, 0, 0, 0);

                if (date >= normalizeBeginDt && date < normalizeEndDt)
                    flgReturn = true;
            }
            return flgReturn;
        }, //end of _isDateInRange()

        _dateDeserialize: function (dateStr, formatStr) {
            //trace("tripDatePicker:_dateDeserialize dateStr = " + dateStr);
            if (formatStr != undefined && formatStr != null && formatStr != '') {
                return eval('new' + dateStr.replace(/\//g, ' ')).format(formatStr);
            }
            else
                return eval('new' + dateStr.replace(/\//g, ' '));
        },

        _dateGet: function (date, formatStr) {
            if (formatStr != undefined && formatStr != null && formatStr != '') {
                return date.format("mmm dd yyyy");
            }
            else
                return date.format(formatStr);
        }

    })

})(jQuery);
