function ContentLoader(placeholderId, url, data) {
    this.placeHolder = $('#' + placeholderId);
    this.error = null;
    this.progressContent = null;
    this.progressbar = null;
    this.progressCount = 0;
    this.content = null;

    this.url = url;
    this.data = data == null ? {} : data;

    this.loaded = false;

    this.OnLoaded = null;

    this.init();
}

ContentLoader.prototype.init = function() {
    this.content = $('<div></div>');
    this.placeHolder.append(this.content);
    this.content.hide();

    this.progressContent = $('<div style="padding:10px;"><center><div class="progressbar" style="width: 200px; height: 10px;"></div>Loading...</center></div>');
    this.placeHolder.append(this.progressContent);

    this.progressbar = $('div.progressbar', this.progressContent);
    this.progressbar.progressbar();
    this.progressContent.hide();

    this.error = $('<div class="error"></div>');
    this.error.hide();
    this.placeHolder.append(this.error);
}

ContentLoader.prototype.load = function() {
    var oThis = this;

    if (!oThis.loaded) {
        if (oThis.error.is(':visible')) {
            oThis.error.fadeOut('slow', function() {
                oThis.loadContent();
            });
        }
        else {
            oThis.loadContent();
        }
    }
}

ContentLoader.prototype.onSuccess = function(html) {
    var oThis = this;

    this.loaded = true;

    this.progressContent.fadeOut('slow', function() {
        oThis.content.html(html);
        oThis.content.fadeIn('slow');
    });

    if (this.OnLoad != null) {
        this.OnLoad();
    }
}

ContentLoader.prototype.onError = function(xhr, status, error) {
    var oThis = this;

    this.progressContent.fadeOut('slow', function() {
        if (status == 'timeout') {
            oThis.showError('Timeout error has occurred. Please try again later.');
        }
        else if (xhr != null) {
            oThis.showError('Error: ' + xhr.status + ' (' + xhr.statusText + ')');
        }
        else {
            oThis.showError('Unknown error has occurred');
        }
    });
}

ContentLoader.prototype.loadContent = function() {
    var oThis = this;

    this.startProgress();

    $.ajax({
        timeout: 60000,
        type: "GET",
        url: oThis.url,
        data: oThis.data,
        success: function(html) {
            oThis.onSuccess(html);
        },
        error: function(xhr, status, error) {
            oThis.onError(xhr, status, error);
        }
    });
}

ContentLoader.prototype.reloadContent = function() {
    var oThis = this;
    this.loaded = false;
    this.progressCount = 0;

    if (this.content.is(':visible')) {
        this.content.fadeOut('slow', function() { oThis.load(); });
    }
    else {
        this.show();
    }
}

ContentLoader.prototype.showError = function(msg) {
    this.error.html('<b>' + msg + '</b>');
    this.error.fadeIn('slow');
}

ContentLoader.prototype.startProgress = function() {
    this.progressContent.fadeIn('slow');
    this.showProgress();
}

ContentLoader.prototype.showProgress = function() {
    var oThis = this;

    this.progressbar.progressbar('value', this.progressbarCount);
    if (this.progressbarCount < 100) {
        this.progressbarCount = this.progressbarCount + 1;
    }
    else {
        this.progressbarCount = 0;
    }

    if (!this.loaded) {
        setTimeout(function() { oThis.showProgress(); }, 50);
    }
}

