var important = '<span class="important"></span>';
var expand = '<span class="expand"></span>';
var collapse = '<span class="collapse"></span>';
var chart = '<span class="chart"></span>';
var table = '<span class="table"></span>';
var other = '<span class="other"></span>';

function LoadSetViewerJsonController(id, webpath, rownum, userTimeDifference, hoursId) {
    this.shadedClass = 'shaded';
    this.highlightColor = '#ffb821';
    this.animateBlinkTime = 200;
    this.htmlUtil = new LoadSetViewerHtmlUtil();
    this.id = id;
    this.path = webpath;
    this.rownum = rownum;
    this.target = jQuery("#setViewer"+id+" ul.setviewertarget");
    this.userTimeDifference = userTimeDifference;
    this.hoursId = hoursId;
    this.timezoneOffset = (new Date().getTimezoneOffset() * 60 * 1000) + userTimeDifference;
    this.loadSetObjects = [];

    var ctrl = this;

    //alert('/loadsetviewer/feed?'+'action=getLoadSets'+'&webPath='+this.path+"&maxObjects="+this.rownum);
    jQuery.ajax({
        url: '/loadsetviewer/feed',
        data : ({action : 'getLoadSets', webPath : ctrl.path, maxObjects : ctrl.rownum}),
        type: 'GET',
        cache: false,
        dataType: 'json',
        success: function(json){
            var jsonItems = eval(json);
            jQuery.each(jsonItems, function(i, item) {
                ctrl.loadSetObjects.push(new LoadSetItem(item, ctrl.path, ctrl.timezoneOffset, ctrl.hourId));
            });
            ctrl.repaint();
        },
        error : function (XMLHttpRequest, textStatus, errorThrown) {
            //alert(XMLHttpRequest.status + " + \n"+textStatus + "\n" + errorThrown);
        }
    });

}

//flashes the "updating" message in the header
LoadSetViewerJsonController.prototype.updateAlert = function () {
    var alertMsg = jQuery('#setViewer'+this.id+'_update');
    alertMsg.fadeIn(200).fadeOut(200).fadeIn(200).fadeOut(200).fadeIn(200).fadeOut(500);
};

//repaints the list
LoadSetViewerJsonController.prototype.repaint = function() {
    this.updateAlert();
    var shadeClass = "";
    if(!this.loadSetObjects || this.loadSetObjects.length == 0) {
        return;
    }
    var curdate = this.loadSetObjects[0].firstUpdate;

    this.target.empty();
    this.target.append(this.htmlUtil.buildDateListItem(curdate));
    var ctrl = this;
    jQuery.each(this.loadSetObjects, function(i, item) {
        if(ctrl.htmlUtil.formatDate(curdate) != ctrl.htmlUtil.formatDate(item.firstUpdate)) {
            curdate = item.firstUpdate;
            ctrl.target.append(ctrl.htmlUtil.buildDateListItem(curdate));
            shadeClass = ctrl.shadedClass;
        }
        ctrl.target.append(item.getHtml(shadeClass));
        shadeClass = shadeClass == '' ? ctrl.shadedClass : '';
    });
};

LoadSetViewerJsonController.prototype.addLoadSet = function(loadSetItem) {
    if(!this.updateLoadSetProgressIfExists(loadSetItem)) {
        var curdate = this.loadSetObjects[0].eventDate;
        var shadeClass = this.target.find('li').eq(1).hasClass(this.shadedClass) ? '' : this.shadedClass;

        if(this.htmlUtil.formatDate(curdate) != this.htmlUtil.formatDate(loadSetItem.eventDate)) {
            this.target.prepend(this.htmlUtil.buildDateListItem(loadSetItem.eventDate));
            shadeClass = '';
        }

        if(!loadSetItem.loadSetObjects) {
            loadSetItem.loadSetObjects = [{}];
        }

        this.loadSetObjects.unshift(loadSetItem);

        var lsiObject = new LoadSetItem(loadSetItem, this.path, this.timezoneOffset, this.hourId);
        this.loadSetObjects.unshift(lsiObject);
        this.loadSetObjects.pop();
        this.target.find('li.groupdate:first').after(lsiObject.getHtml(shadeClass));
        lsiObject.animateListItem(this.highlightColor);

        return loadSetItem;
    }
};

LoadSetViewerJsonController.prototype.updateLoadSetProgressIfExists = function(loadSetItem) {
    var exists = false;
    var ctrl = this;
    jQuery.each(this.loadSetObjects, function (i, item) {
        if(item.setId == loadSetItem.setId && item.setTypeId == loadSetItem.setTypeId
                && item.runDate == loadSetItem.runDate
                && loadSetItem.eventDate > item.eventDate) {  //only loadsets with newer than previous event should be updated
            ctrl.updateAlert();
            exists = item.updateProgress(loadSetItem);
        }
    });
    return exists;
};

/*
 example loadset json structure
 "setId":2732,
 "setTypeId":1,
 "eventDate":"Oct 22, 2009 12:00:00 AM",
 "code":"Starting",
 "partialNumber":0,
 "partialTotal":0,
 "infoMessage":"7 mw up today!",
 "setTitle":"Temperature GFS Operational",
 "runDate":"Oct 22, 2009 12:00:00 AM",
 "webPath":"/trading/pmtnp/weather/temperature/forecast/sweden/gfs00",
 "hour":0
 */
function LoadSetItem(jsonItem, path, tzOffset, hourId) {
    this.jsonItem = jsonItem;

    this.setId = jsonItem.setId;
    this.setTypeId = jsonItem.setTypeId;
    this.eventDate = parseInt(jsonItem.eventDate);
    this.runDate = parseInt(jsonItem.runDate);
    if(jsonItem.firstUpdate != null) {
        this.firstUpdate = parseInt(jsonItem.firstUpdate);
    } else {
        this.firstUpdate = this.eventDate;
    }
    this.partialNumber = jsonItem.partialNumber;
    this.partialTotal = jsonItem.partialTotal;

    this.webPath = path;
    this.expanded = false;
    this.tzOffset = tzOffset;
    this.hourId = hourId;

    this.htmlRef = null;
    this.innerTarget = null;

    this.loadSetObjects = [];
}


LoadSetItem.prototype.getHtml = function(styleClass) {

    var name = this.buildNameElement();
    var info = jQuery(document.createElement('span')).addClass('info').html(this.jsonItem.infoMessage);

    var innerTarget = jQuery(document.createElement('ul')).addClass('objectList ' + this.setId);

    var isComplete = this.partialNumber == this.partialTotal;
    if(isComplete) {
        styleClass = styleClass + ' complete';
    }

    if(this.jsonItem.infoMessage && this.jsonItem.infoMessage.length > 0) {
        styleClass = styleClass + ' hasInfoMessage';
    }

    var listItem = jQuery(document.createElement('li'))
            .append(name)
            .append(this.buildProgressBar(this.setId, this.partialNumber, this.partialTotal))
            .append(info)
            .append(innerTarget)
            .addClass(styleClass);

    this.htmlRef = listItem;
    this.innerTarget = innerTarget;
    innerTarget.css('display', 'none');

    return listItem;
};

LoadSetItem.prototype.updateProgress = function(updatedJsonItem) {
    this.partialNumber = updatedJsonItem.partialNumber;
    var perc = Math.floor((this.partialNumber / this.partialTotal) * 100);
    //just in case something silly happens
    if(!perc || perc == NaN) perc = 0;

    if(perc == 100) {
        this.htmlRef.find("span.progressbar").hide();
        this.htmlRef.find('span.name').addClass('complete');
        new LoadSetViewerHtmlUtil().animateNewElement(this.htmlRef, 15000);
    } else {
        this.htmlRef.find("span.progressbar")
                .progressBar(perc)
                .fadeOut(500).fadeIn(500).fadeOut(500).fadeIn(500);
    }

    if (this.htmlRef.find("span.info").html() != updatedJsonItem.infoMessage) {
        this.htmlRef.find("span.info").html(updatedJsonItem.infoMessage)
        .fadeOut(500).fadeIn(500).fadeOut(500).fadeIn(500);
    }

    this.htmlRef.find("a.lsName").attr('title', 'Last update: ' + new LoadSetViewerHtmlUtil().formatTime(updatedJsonItem.eventDate, this.tzOffset, this.hourId));

    return true;
};

LoadSetItem.prototype.buildNameElement = function() {
    var expand = jQuery(document.createElement('a')).addClass('expander expand');
    var ctrl = this;


    expand.bind('click', function(e) {
        ctrl.expanded ? ctrl.collapseobjectList(ctrl.jsonItem) : ctrl.expandObjectList(ctrl.jsonItem, 'MAJOR');
        ctrl.htmlRef.find('.expander').toggleClass('collapse').toggleClass('expand');
    });
    var time = new LoadSetViewerHtmlUtil().formatTime(this.firstUpdate, this.tzOffset, this.hourId);
    var lsName = jQuery(document.createElement('a'))
            .addClass('lsName')
            .attr('href',this.jsonItem.webPath)
            .attr('title', 'Last update: ' + new LoadSetViewerHtmlUtil().formatTime(this.eventDate, this.tzOffset, this.hourId))
            .html(time + ' ' + this.jsonItem.setTitle);
    var nameClass = 'name';

    return jQuery(document.createElement('span')).addClass(nameClass)
            .append(expand)
            .append(lsName);
};

LoadSetItem.prototype.animateListItem = function(highlightColor) {
    var ctrl = this;
    jQuery(this.htmlRef).css({'background-color': highlightColor})
            .fadeOut(300).fadeIn(300).fadeOut(300).fadeIn(300, function() {
        jQuery(ctrl.htmlRef).css('background-color', '');
    });
    return this.jsonItem;
};

/*
 example loadset object json structure
 "objectId":100004114,
 "objectTypeId":3,
 "objectType":"Chart",
 "objectTitle":"Title",
 "webPath":"/trading/pmtnp/supply/hydro/benchmark/nordpool",
 "priority":"MINOR",
 "breadcrumb" : "xxx > yyy > zzz"
 */
LoadSetItem.prototype.buildLoadSetObjectHtml = function(loadSetObjectItem, shadeClass) {
    if(loadSetObjectItem && loadSetObjectItem.webPath) {
        var objectType = other;
        if(loadSetObjectItem.objectTypeId == 3) objectType = chart;
        if(loadSetObjectItem.objectTypeId == 4) objectType = table;

        var objectUrl = loadSetObjectItem.webPath ? loadSetObjectItem.webPath : '#';

        var breadcrumbItem = this.buildBreadcrumbItem(loadSetObjectItem.breadcrumb);

        var objectLink = jQuery(document.createElement('a'))
                .attr('href', objectUrl)
                .attr('title', objectUrl)
                .html(loadSetObjectItem.objectTitle);

        var objectListItem = jQuery(document.createElement('li'))
                .append(objectType)
                .append(objectLink);


        //if(loadSetObjectItem.priority == 'MAJOR') objectListItem.append(important);
        objectListItem.append(breadcrumbItem)
                    .addClass(shadeClass);
        return objectListItem;
    }
    return null;
};

LoadSetItem.prototype.buildBreadcrumbItem = function(breadcrumb) {
    var bci = breadcrumb.split(">");
    bci.reverse();
    var bci2 = "";
    for(var i = 0 ; i< bci.length - 2 ; i++) {
       bci2 += ' < ' + bci[i].replace(' ', '');
    }
    //breadcrumb = breadcrumb.replace(bci[0], "").replace(bci[1], "").replace('>>', '');
    breadcrumb = bci2;

    return jQuery(document.createElement('span'))
            .addClass('breadcrumb')
            .html(breadcrumb);
};

LoadSetItem.prototype.buildProgressBar = function(id, completed, total) {
    var perc = 0;
    if(total != 0) {
        perc = Math.floor((completed / total) * 100);
        //just in case something silly happens
        if(!perc || perc == NaN) perc = 0;
    }

    if (perc != 100) {
        return jQuery(document.createElement('span'))
                .addClass('progressbar')
                .progressBar(perc, {
            width:50,
            showText : false,
            boxImage : '/images/progressbar/progressbar.gif',
            barImage : '/images/progressbar/progressbg_green.gif'
            });

    }
};

//show load set object list
LoadSetItem.prototype.expandObjectList = function(listItem, priority) {
    var ctrl = this;
    if(priority == 'MINOR' || ctrl.innerTarget.find('li').length < 1) {
        ctrl.innerTarget.empty();

        //alert('/loadsetviewer/feed?action=getObjects'+'&webPath='+ctrl.webPath +"&loadSetId="+listItem.setId+"&hour="+listItem.hour + '&priority='+priority);
        jQuery.ajax({
            type: 'GET', cache: false, dataType: 'json',
            url: '/loadsetviewer/feed',
            data : {action : 'getObjects', webPath :  ctrl.webPath, loadSetId : ctrl.setId, hour: listItem.hour, priority : priority},
            success: function(json){
                var loadSetObjects = eval(json);
                ctrl.loadSetObjects = ctrl.loadSetObjects.concat(loadSetObjects);
                ctrl.displayItems();
            },
            error : function (XMLHttpRequest, textStatus, errorThrown) {  //if something went wrong, append error message
                ctrl.innerTarget.append(jQuery(document.createElement('span')).html('There was an error while getting objects for this loadset.'));
                ctrl.slideDownFast(listItem);

            },
            complete : function (XMLHttpRequest, textStatus) {
                ctrl.innerTarget.append(ctrl.buildTogglePriorityButton(ctrl, listItem, priority));
                ctrl.slideDownFast(listItem);
            }
        });

    } else {
        ctrl.slideDownFast(listItem);
    }
    //it seems intuitive to have the slideDownFast call here, but that won't work, because the jQuery.ajax call is asynchronous,
    //and thus if the call is placed here it will fire before the result set is returned.
    ctrl.expanded = true;
};

LoadSetItem.prototype.buildTogglePriorityButton = function(ctrl, listItem, priority) {
    if(priority == 'MAJOR') {
        return jQuery(document.createElement('a'))
                .addClass('togglePriority')
                .html('Show charts/tables with minor priority')
                .bind('click', function(e) {
            ctrl.expandObjectList(listItem, 'MINOR');
        });
    }

    if(priority == 'MINOR') {
        return jQuery(document.createElement('a'))
                .addClass('togglePriority')
                .html('Show charts/tables with minor priority')
                .bind('click', function(e) {
            ctrl.innerTarget.empty();
            ctrl.loadSetObjects = [];
            ctrl.expandObjectList(listItem, 'MAJOR');
        });
    }
    return null;
};

LoadSetItem.prototype.displayItems = function() {
    if(this.loadSetObjects.length < 1) { //if the result is empty, append information message
        //loadSetItem.item.innerTarget.append(jQuery(document.createElement('span')).addClass('innerInfo').html('No objects were found for this loadset.'));
    } else {
        var listClass = parent.listClass == 'shaded' ? '' : 'shaded';
        var ctrl = this;
        jQuery.each(this.loadSetObjects, function(j, iitem) {
            ctrl.innerTarget.append(ctrl.buildLoadSetObjectHtml(iitem, listClass));
            listClass = listClass == 'shaded' ? '' : 'shaded';
        });
    }
    return true;
};

LoadSetItem.prototype.slideDownFast = function(listItem) {
    this.innerTarget.slideDown('fast');
};

//hide load set object list
LoadSetItem.prototype.collapseobjectList = function(listItem) {
    this.innerTarget.slideUp('fast');
    this.expanded = false;
};

function LoadSetViewerHtmlUtil() {}

//create an li node with the date
LoadSetViewerHtmlUtil.prototype.buildDateListItem = function(date) {
    return jQuery(document.createElement('li'))
            .addClass('greyongradwhite groupdate')
            .html(this.formatDate(date));
};

LoadSetViewerHtmlUtil.prototype.formatDate = function(date) {
    var d = new Date(date);
    return d.toDateString();
};

LoadSetViewerHtmlUtil.prototype.formatTime = function(date, offset, hourId) {
    var adjDate = new Date(date);
    adjDate.addMilliseconds(offset);
    var formatString ="HH:mm:ss";
    if (hourId == '12') {
        formatString = formatString.replace("HH", "hh") + ' tt';
    }
    return adjDate.toString(formatString);
};

LoadSetViewerHtmlUtil.prototype.animateNewElement = function(target, animateTime) {
    target.css({"background-color":"#ffb821", "display":"block"});
    target.find("a").css({"color":"white", "font-weight": "bold"});
    target.find("em").css({"color":"white","font-weight": ""});
    target.fadeOut(200).fadeIn(200).fadeOut(200).fadeIn(200);
    setTimeout(function(){new LoadSetViewerHtmlUtil().normalize(target);}, animateTime);
};

LoadSetViewerHtmlUtil.prototype.normalize = function(target) {
    target.css({"background":"#fff","display":"block"}, 200);
    target.find("a").css({"color":"","font-weight": ""});
    target.find("em").css({"color":"", "font-weight": ""});
};