 
var KMC = {

    page: 0,

    on_change_month: function (e) {
        var new_month = KMC.CALENDAR.date.getMonth() + (e.target.id === 'prev_month' ? -1 : 1);
        var new_year = KMC.CALENDAR.date.getFullYear();
        if (new_month > 11) { 
            new_year++;
            new_month = 0; 
        }
        if (new_month < 0) {
            new_year = new_year - 1;
            new_month = 11;
        } 

        KMC.CALENDAR.date.setMonth(new_month);
        KMC.CALENDAR.date.setFullYear(new_year);
        KMC.DATA.get_shifts(KMC.CALENDAR.draw.createDelegate(KMC.CALENDAR));
    },

    auth: function () {
        return KMC.user !== 'AnonymousUser';
    },

    register_events: function () {

        $("#save_link, #signin_link").fancybox({
            'titlePosition': 'inside',
            'transitionIn': 'none',
            'transitionOut': 'none',
            onClosed: function() { // re-enable the disabled save button.
                var $submit = $('#shift_submit');
                if ($submit.length) $submit.get(0).disabled=false;
            }
        });

        // Calendar event handler.
        $('body').live('click', function (evt) {
            // the first class must contain a string "_view" to automatically link to a view.
            var $tgt = $(evt.target);
            
            // get the first class of either the click target or it's parent. this used to choose a view.
            var view_name = $tgt.attr('class').split(" ")[0];
            if (!view_name) view_name=$tgt.parent().attr('class').split(" ")[0];
            
            // generic VIEW handler.
            if (/_view/.test(view_name)) {

                if (KMC.VIEWS[view_name]) {
                    var $tgt = $(evt.target),
                        day_of_month;
                    if (view_name === 'shift_view') {
                            var index = parseInt($tgt.attr('id').match(/shift_(\d+)/)[1]);
                            var shift = KMC.shifts[index];
                            day_of_month = $tgt.parent().attr('id').replace('day_', '') * 1;
                            // if we clicked inside the calendar, redraw the date as well.
                            KMC.VIEWS.shift_view(shift, day_of_month);
                        }
                    else if (view_name === 'day_view') {
                            KMC.VIEWS.day_view($tgt.parent().attr('id').replace("day_", "") * 1);

                            // handle clicks to the history view controls.
                        }
                    else if (view_name === 'shift_history_view' || view_name === 'history_view') {

                            if ($tgt.text() === "previous") {
                                KMC.page = KMC.page - KMC.num_per_page;
                            }
                            else if ($tgt.text() === "next") {
                                KMC.page = KMC.page + KMC.num_per_page;
                              
                            }
                            else {
                                KMC.page = 0;
                            }

                            if (view_name === 'shift_history_view') {
                                KMC.VIEWS.shift_history_view();
                            }
                            else if (view_name === 'history_view') {
                                KMC.VIEWS.history_view();
                            }
                        }
                    // get the view with name equal to the class of the element clicked.
                    KMC.CALENDAR.calendar_size = 'mini';
                    KMC.CALENDAR.draw();
                }
                else {
                    alert(view_name + " is not a valid view.");
                }

                // Tabs click handler
            }
            else if ($tgt.parents("ul#tabs").length > 0) {
                KMC.$view.hide();

                var shift_type_id = $tgt.attr('id').replace('shift_type_', '');
                $('#tabs li.active').removeClass('active');
                $tgt.addClass('active');
                KMC.shift_type = KMC.shift_types[shift_type_id];
                KMC.DATA.get_shifts(KMC.CALENDAR.draw.createDelegate(KMC.CALENDAR));
                KMC.$view.empty();
                KMC.$view2.empty();

            }
            else if ($tgt.hasClass('btn')) {
                KMC.BUTTONS.click($tgt);
            }
            else if ($tgt.hasClass('date_type_toggle')) {
                KMC.VIEWS.date_type_toggle($tgt);
            }
        });
    },

    update_signin_link: function () {
        if (KMC.auth()) {
            $(".private").show();
            $("#signin_link").hide();
            $("#signout_link,#admin_link,#history_link").show();
        }
        else {
            $(".private").hide();
            $("#signin_link").show();
            $("#signout_link,#admin_link,#history_link").hide();
        }
    },
    
    update_local_shift: function (shift_rsp){
        shift = new KMC.Shift(
            KMC.UTIL.first_item(
                shift_rsp
            )
        );
        
        // if the returned shift is on the currently viewed day, show it.
        if( KMC.CALENDAR.date.showShift(shift)) {
            KMC.shift = shift;
        } else {
            delete KMC.shift;
        }
    },
    handle_save_response:function (rsp) {
        response = KMC.UTIL.parse_json(rsp);
        
        if (!response.success){
        
            KMC.UTIL.popup(response.message);
        
        }
        
        if(response.future_shift){
            KMC.update_local_shift(response.future_shift);
        }
        if(response.shift){
            KMC.update_local_shift(response.shift);
        }
        
        KMC.DATA.get_shifts(function() {
            if( KMC.shift ){
                KMC.VIEWS.shift_view(KMC.shift, KMC.CALENDAR.date.getDate());
            } else {
            
                KMC.VIEWS.day_view(KMC.CALENDAR.date.getDate());
            }
            $("#fancybox-close").click();
            KMC.UTIL.popup("Shift succesfully updated.");
        });
        //TODO: possibly optimise to only sync the changed shift
    },
    save_delete_handler: function (deleted){

                KMC.save_data = {deleted: deleted
                    };
                $('form input').add('form textarea').add('form select').each(function (i, item) {
                    if (item.name) {
                        KMC.save_data[item.name] = item.value;
                        if (KMC.DATA.validate[item.name]
                            && !KMC.DATA.validate[item.name](item.value)) invalid = true;
                        if (item.name.indexOf("_month") > -1) {
                            KMC.save_data[item.name] = KMC.save_data[item.name] * 1 + 1;
                        }
                    }
                });
                KMC.save_data.sendEmail= $('form input#sendEmail').get(0).checked;

                if (KMC.shift.id) KMC.save_data.id = KMC.shift.id;
                if (KMC.shift.id && (KMC.shift.end_date === 'None' 
                        || (KMC.shift.end_date.daysBetween(KMC.CALENDAR.date)) >= 7) ){
                    // simulate a link click to bring up fancybox plugin.
                    $('#save_link').click();
                } else {
                    if (KMC.shift.id) KMC.save_data.all_weeks = 1;
                    //if (KMC.shift.id && !deleted && (new Date()) > KMC.shift.start_date) KMC.save_data.all_weeks = 1;
                    KMC.save_data.now = KMC.CALENDAR.date.si_format({
                        hours: false,
                        minutes: false,
                        seconds: false
                    });
                    $.post('/shift/', KMC.save_data, KMC.handle_save_response);
                }
    },
    BUTTONS: {
        
        click: function ($button) {
            

            // SAVE button handler.
            if ($button.val() === 'save') {
                var curr_date = new Date();
                if(curr_date.setDate(curr_date.getDate()-1) <= KMC.CALENDAR.date){
                    $button.get(0).disabled = true;
                    KMC.save_delete_handler(false);
                }
                else
                {
                    alert("This shift has already occurred and has been locked for editing");
                }
            }
            
            // NEW button handler.
            if ($button.val() === 'new shift') {
                // get a doctor
                var first_doctor;
                for (d in KMC.doctors) {
                    first_doctor = KMC.doctors[d];
                    break;
                }
                // populate the form with sensible defaults.
                var new_shift = new KMC.Shift({
                    id: '',
                    start_date: KMC.CALENDAR.date.clone(),
                    start_time: new Date(1970, 0, 0, 9, 0),
                    end_date: KMC.CALENDAR.date.clone(),
                    end_time: new Date(1970, 0, 0, 17, 0),
                    shift_type: KMC.shift_type,
                    doctor: first_doctor,
                    notes: ''
                }, true);

                KMC.VIEWS.shift_view(new_shift);
            }
            
            // DELETE button
            if ($button.val() === 'delete') {
                 var curr_date = new Date();
                if(curr_date.setDate(curr_date.getDate()-1) <= KMC.CALENDAR.date){
                    $button.get(0).disabled = true;
                    KMC.save_delete_handler(true);
                }
                else
                {
                    alert("This shift has already occurred and has been locked for editing");
                }

            }
            
            // REMIND button
            if ($button.val() === 'send reminder') {
                $.post('/remind/'
                    + KMC.CALENDAR.date.getFullYear() + '/'
                    + (KMC.CALENDAR.date.getMonth() + 1) + '/'
                    + KMC.CALENDAR.date.getDate(), {
                        shift: KMC.shift.id
                }, function (rsp) {
                    rsp = KMC.UTIL.parse_json(rsp);
                    if (rsp.success) {
                        KMC.UTIL.popup("reminder sent.");
                    } else {
                        KMC.UTIL.popup("sending reminder failed.");
                    }
                });
            }
            
            // SIGN IN button handler (after entering password)
            if ($button.val() === 'sign in') {
                $.post('/sign_in', {
                    user: $('input[name="user"]').val(),
                    password: $('input[name="password"]').val()
                }, function (rsp) {
                    rsp = eval("(" + rsp + ")");
                    if (rsp.success){
                        $.fancybox.close();
                        KMC.user = rsp.user;
                        KMC.update_signin_link();
                        
                        if(KMC.shift) {
                            KMC.VIEWS.shift_view(KMC.shift, KMC.CALENDAR.date.getDate());   
                        }
                        else if(KMC.VIEWS.day_view(KMC.CALENDAR.date.getDate())){
                            KMC.VIEWS.shift_view(KMC.shift, KMC.CALENDAR.date.getDate());
                        }
                    }
                    else {
                        alert("You have entered the wrong password/user combination....")
                    }
                });
            }
            // Sign_out button handler
            
            if ($button.text() === 'sign out') {
                $.post('/sign_out', function (rsp) {
                    rsp = eval("(" + rsp + ")");
                    KMC.user = rsp.user;
                    KMC.update_signin_link();
                    KMC.update_signin_link();
                    if(KMC.shift)
                         KMC.VIEWS.shift_view(KMC.shift, KMC.CALENDAR.date.getDate());
                    //alert(rsp);
                });
            }
            
            //
            if ($button.attr('id') == 'save_1_week') {
                KMC.save_data.one_week = 1;
                KMC.save_data.now = KMC.CALENDAR.date.si_format({
                    hours: false,
                    minutes: false,
                    seconds: false
                });
                $.post('/shift/', KMC.save_data, KMC.handle_save_response);
            } 
            
            if ($button.attr('id') == 'save_all_weeks') {
                KMC.save_data.all_weeks = 1;
                KMC.save_data.now = KMC.CALENDAR.date.si_format({
                    hours: false,
                    minutes: false,
                    seconds: false
                });
                $.post('/shift/', KMC.save_data, KMC.handle_save_response);
            }

        }

    },

    DATA: {
        
        validate: {
            doctor: function(val) {
                return true;
            }
        
        },
        
        get_shifts: function (fn) {
            var shift_type = KMC.shift_type;
            var year = KMC.CALENDAR.date.getFullYear();
            var month = KMC.CALENDAR.date.getMonth();
            KMC.CALENDAR.calendar_size = 'full';

            $.getJSON("/ajax/shifts/" + shift_type.id + "/" + year + "/" + month, function (json) {
                var start_date, end_date, shift;
                KMC.shifts = {};
                for (x in json) {
                    KMC.shifts[x] = new KMC.Shift(json[x]);
                }
                if (fn) fn();
            });
        }
    }

};

$().ready(function () {

    KMC.$view = $('#view').hide();
    KMC.$view2 = $('#view2').hide();

    KMC.register_events();
    for (x in KMC.doctors) {
        KMC.doctors[x] = new KMC.Doctor(KMC.doctors[x]);
    }
    for (x in KMC.shift_types) {
        KMC.shift_types[x] = new KMC.ShiftType(KMC.shift_types[x]);
    }

    // buttons for switching the month.
    $('#prev_month').click(KMC.on_change_month);
    $('#next_month').click(KMC.on_change_month);

    KMC.update_signin_link();

    // auto-select time and date inputs when the user clicks them.
    $('span.time-input input, span.date-input input').live('click', function (evt) {
        this.select();
    });

    $('#tabs li').eq(0).click();
    $().pngFix(); //fix transparency in ie6
    
    $('#signin_password').keyup(function (evt) {
       if(evt.which == 13){
           $('#signin_submit').click();
       }
    });
});

// object model which knows about various serialized json objects dumped from a Django database.
// javascript dates are evaluted and foreign keys are resolved, assuming all such tables, must
// exist with in the provided scope (@param).
KMC.OBJ = {

    // set the scope which contains all object conforming to our object model.
    init: function (scope) {
        this.scope = scope;
    },

    get_from_json: function (obj, data) {
        var the_date, m, field_name, field_value;
        obj.fields = [];

        for (key in data) {
            field_name = key;
            // convert json date into javascript date.
            if (typeof data[key] == 'string' && data[key].match(/^new\sDate/)) {
                eval('the_date=' + data[key]);
                field_value = the_date;
            }
            else {
                m = key.match(/^(.*)_id$/);
                // foreign key references end in "_id"       
                if (m) {
                    field_name = m[1];
                    field_value = this.scope[m[1] + 's'][data[key]];
                }
                else {
                    // if not a date or foreign key, use literally.
                    field_value = data[key];
                }
                obj[key] = data[key]; // keep a reference to the shift id.
            }
            obj[field_name] = field_value;
            obj.fields.push(field_name);
        }
    },

    METHODS: {

        print: function () {
            var html = '';
            var item;
            var output_value;
            for (var i = 0; i < this.fields.length; i++) {
                item = this[this.fields[i]];
                if (item instanceof Date) {
                    output_value = item.printTime();
                }
                else {
                    output_value = item;
                }
                html += this.fields[i] + ' : ' + output_value + "<br/>";

            }
            return html;
        },

        input: function () {
            var html = '<select name="' + this._class + '">';
            var collection = KMC.OBJ.scope[this._class + 's'];
            var keys = KMC.UTIL.sorted_keys(collection,this.order_by || 'id');

            for (var mk in keys) {
                key = keys[mk];
                html += '<option ' + (collection[key].id == this.id ? 'selected = "selected" ' : '') + 'value = "' + collection[key].id + '">' + collection[key] + '</option>';
            }
            html += '</select>';
            return html;
        }

    },

    // generate a class for holding data from the server.
    DataClass: function (_class, opts) {

        // this is the constructor.
        cls = function (data, from_literal) {
            if (from_literal) {
                $.extend(this, data);
            }
            else {
                KMC.OBJ.get_from_json(this, data);
            }
        };
        for (method in this.METHODS) {
            cls.prototype[method] = this.METHODS[method];
        }
        cls.prototype._class = _class;
        $.extend(cls.prototype, opts);
        return cls;
    }
};

KMC.OBJ.init(KMC); // set the object model scope to be KMC.
KMC.Shift = KMC.OBJ.DataClass('shift');
KMC.Doctor = KMC.OBJ.DataClass('doctor', {order_by:'first_name'});
KMC.ShiftType = KMC.OBJ.DataClass('shift_type');
KMC.History = KMC.OBJ.DataClass('history');

KMC.ShiftType.prototype.toString = KMC.Doctor.prototype.toString = function () {
    return this.name || this.first_name;
};

