function PhotoPlayer(objectName, interval, nextButtonId, prevButtonId, pausePlayButtonId,
                     nextButtonImageUrl, nextButtonPressedImageUrl,
                     prevButtonImageUrl, prevButtonPressedImageUrl,
                     pauseButtonImageUrl, pauseButtonPressedImageUrl,
                     playButtonImageUrl, playButtonPressedImageUrl,
                     autoRotateBios, prevButtonDisabledImageUrl, isPrevDisabledOnStart, startFromRandomNumber) {
    this._objectName = objectName;
    this._nextButtonId = nextButtonId;
    this._prevButtonId = prevButtonId;
    this._pausePlayButtonId = pausePlayButtonId;
    this._interval = interval;

    this._nextButtonImageUrl = nextButtonImageUrl;
    this._nextButtonPressedImageUrl = nextButtonPressedImageUrl;
    this._prevButtonImageUrl = prevButtonImageUrl;
    this._prevButtonPressedImageUrl = prevButtonPressedImageUrl;
    this._pauseButtonImageUrl = pauseButtonImageUrl;
    this._pauseButtonPressedImageUrl = pauseButtonPressedImageUrl;
    this._playButtonImageUrl = playButtonImageUrl;
    this._playButtonPressedImageUrl = playButtonPressedImageUrl;

    this._autoRotateBios = autoRotateBios;

    this._prevButtonDisabledImageUrl = prevButtonDisabledImageUrl;
    this._isPrevDisabledOnStart = isPrevDisabledOnStart;
    this._startFromRandomNumber = startFromRandomNumber;
}

PhotoPlayer.prototype =
{
    _objectName: null,
    _bios: null,
    _currentPhotoIndex: null,
    _currentBioIndex: null,
    _nextButtonId: null,
    _prevButtonId: null,
    _pausePlayButtonId: null,
    _timeoutValue: 0,
    _photoShowingTimeoutValue: 0,
    _interval: null,
    _isPlaying: null,
    _disableButtons: null,
    _btnPrevDisabled: null,

    _nextButtonImageUrl: null,
    _nextButtonPressedImageUrl: null,
    _prevButtonImageUrl: null,
    _prevButtonPressedImageUrl: null,
    _pauseButtonImageUrl: null,
    _pauseButtonPressedImageUrl: null,
    _playButtonImageUrl: null,
    _playButtonPressedImageUrl: null,

    _autoRotateBios: null,

    _prevButtonDisabledImageUrl: null,
    _isPrevDisabledOnStart: null,

    _fadeInterval: 700,
    _fadeInDelay: 0,
    _startFromRandomNumber: null,
    _playCallback: null,

    initialize: function(bios) {
        this._currentPhotoIndex = 0;
        this.registerEventHandlers();
        this._bios = bios;
        var biosCount = this._bios.length;
        if (this._startFromRandomNumber) {
            this._currentBioIndex = Math.floor(biosCount * Math.random());
        }
        else {
            this._currentBioIndex = 0;
        }
        this.addBio(this._bios[this._currentBioIndex], 2, true);
        if (this._autoRotateBios && biosCount > 1) {
            var prevBioIndex = this._currentBioIndex == 0 ? biosCount - 1 : this._currentBioIndex - 1;
            this.addBio(this._bios[prevBioIndex], 1, false, false);
        }
        this._timeoutValue = window.setTimeout(this._objectName + '.switchView(true)', this._interval);
        this._isPlaying = true;
        this._disableButtons = false;
        if (this._isPrevDisabledOnStart) {
            this.disablePrevButton();
        }
        else {
            this.enablePrevButton();
        }
    },

    addBio: function(biography, initialPhotosCount, visible, forward) {
        var ul = $("#bios");
        var li = $("<li></li>")
                        .attr("id", "bio" + biography._id)
                        .css(
                        {
                            display: visible ? "block" : "none"
                        })
                        .appendTo(ul);
        var divPhotos = $("<div class='photos'></div>").appendTo(li);
        var ulPhotos = $("<ul></ul>")
                    .attr("id", "photos" + biography._id)
                    .appendTo(divPhotos);
        if (forward == false) {
            for (var i = biography._photos.length - 1; i >= 0; i--) {
                this.addPhoto(biography._photos[i], biography._id, i == biography._photos.length - 1);
            }
        }
        else {
            for (var i = 0; i < initialPhotosCount && i < biography._photos.length; i++) {
                this.addPhoto(biography._photos[i], biography._id, i == 0);
            }
            if (initialPhotosCount > biography._photos.length && biography._id + 1 < this._bios.length) {
                this.addBio(this._bios[biography._id + 1], initialPhotosCount - biography._photos.length, false);
            }
        }
        var divData = $("<div class='data'></div>").appendTo(li);
        $("<div class='name'>" + biography._name + "</div>").appendTo(divData);
        $("<div class='descr'>" + biography._description + "</div>").appendTo(divData);
    },

    addPhoto: function(photo, biographyId, visible) {
        var parent = $("#photos" + biographyId)

        var li = $("<li></li>")
                            .attr("id", "photo" + biographyId + "_" + photo._id)
                            .css(
                            {
                                display: visible ? "block" : "none"
                            })
                            .appendTo(parent);
        var name = this._bios[biographyId]._name;
        var img = $("<img></img>")
                    .attr("src", photo._path)
                    .attr("alt", name)
                    .attr("title", name)
                    .appendTo(li);

        var imgHeight = img.attr("height");
        if (imgHeight != 0 && imgHeight < 250) {
            img.css(
        			{
        			    "margin-top": "34px"
        			});
        }
    },

    registerEventHandlers: function() {
        this.getNextControl().click(this.onNextButtonClick.createDelegate(this));
        this.getPrevControl().click(this.onPrevButtonClick.createDelegate(this));
        this.getPausePlayControl().click(this.onPausePlayButtonClick.createDelegate(this));

        this.getNextControl().mousedown(this.onNextButtonMouseDown.createDelegate(this));
        this.getNextControl().mouseup(this.onNextButtonMouseUp.createDelegate(this));
        this.getNextControl().mouseout(this.onNextButtonMouseUp.createDelegate(this));

        this.getPrevControl().mousedown(this.onPrevButtonMouseDown.createDelegate(this));
        this.getPrevControl().mouseup(this.onPrevButtonMouseUp.createDelegate(this));
        this.getPrevControl().mouseout(this.onPrevButtonMouseUp.createDelegate(this));

        this.getPausePlayControl().mousedown(this.onPausePlayButtonMouseDown.createDelegate(this));
        this.getPausePlayControl().mouseup(this.onPausePlayButtonMouseUp.createDelegate(this));
        this.getPausePlayControl().mouseout(this.onPausePlayButtonMouseUp.createDelegate(this));
    },

    onNextButtonMouseDown: function() {
        this.getNextControl().attr("src", this._nextButtonPressedImageUrl);
    },
    onNextButtonMouseUp: function() {
        this.getNextControl().attr("src", this._nextButtonImageUrl);
    },
    onPrevButtonMouseDown: function() {
        if (!this._btnPrevDisabled) {
            this.getPrevControl().attr("src", this._prevButtonPressedImageUrl);
        }
    },
    onPrevButtonMouseUp: function() {
        if (!this._btnPrevDisabled) {
            this.getPrevControl().attr("src", this._prevButtonImageUrl);
        }
    },
    onPausePlayButtonMouseDown: function() {
        if (this._isPlaying) {
            this.getPausePlayControl().attr("src", this._pauseButtonPressedImageUrl);
        }
        else {
            this.getPausePlayControl().attr("src", this._playButtonPressedImageUrl);
        }
    },
    onPausePlayButtonMouseUp: function() {
        if (this._isPlaying) {
            this.getPausePlayControl().attr("src", this._pauseButtonImageUrl);
        }
        else {
            this.getPausePlayControl().attr("src", this._playButtonImageUrl);
        }
    },

    onNextButtonClick: function() {
        if (!this._disableButtons) {
            this._timeoutValue = window.clearTimeout(this._timeoutValue);
            this.switchView(true);
            this.onPlayButtonClick();
        }
    },

    onPrevButtonClick: function() {
        if (!this._disableButtons && !this._btnPrevDisabled) {
            this._timeoutValue = window.clearTimeout(this._timeoutValue);
            this.switchView(false);
            this.onPlayButtonClick();
        }
    },

    onPausePlayButtonClick: function() {
        //if (!this._disableButtons) {
        this._timeoutValue = window.clearTimeout(this._timeoutValue);
        if (!this._isPlaying) {
            this.switchView(true);
            this.onPlayButtonClick();
        }
        else {
            this.onPauseButtonClick();
        }
        //}
    },
    onPauseButtonClick: function() {
        this.getPausePlayControl().attr("src", this._playButtonImageUrl);
        this._isPlaying = false;
    },
    onPlayButtonClick: function() {
        this.getPausePlayControl().attr("src", this._pauseButtonImageUrl);
        this._isPlaying = true;
        if (this._playCallback) {
            this._playCallback.call();
        }
    },

    switchView: function(forward) {
        if (this._autoRotateBios && forward && this._currentPhotoIndex == this.getCurrentBio()._photos.length - 1) {
            this.hideCurrentBio(true);
        }
        else if (this._autoRotateBios && !forward && this._currentPhotoIndex == 0) {
            this.hideCurrentBio(false);
        }
        else {
            this.hideCurrentPhoto(forward);
        }
        if (this._btnPrevDisabled) {
            this.enablePrevButton();
        }
    },

    hideCurrentPhoto: function(forward) {
        this._disableButtons = true;
        this.getCurrentPhoto().fadeOut(this._fadeInterval);
        this._photoShowingTimeoutValue = setTimeout(this._objectName + '.showNextPhoto(' + forward + ')', this._fadeInterval + this._fadeInDelay);
    },

    showNextPhoto: function(forward) {
        var itemsCount = this.getCurrentBio()._photos.length;
        var nextPhotoIndex = this._currentPhotoIndex;
        var photoToAddIndex = nextPhotoIndex;
        var bioToAddIndex = this._currentBioIndex;
        if (forward) {
            nextPhotoIndex++;
            nextPhotoIndex = nextPhotoIndex == itemsCount ? 0 : nextPhotoIndex;

            photoToAddIndex = nextPhotoIndex + 1;
            if (photoToAddIndex == itemsCount) {
                photoToAddIndex = 0;
                bioToAddIndex++;
                bioToAddIndex = bioToAddIndex == this._bios.length ? 0 : bioToAddIndex;
            }
        }
        else {
            nextPhotoIndex--;
            nextPhotoIndex = nextPhotoIndex == -1 ? itemsCount - 1 : nextPhotoIndex;

            photoToAddIndex = nextPhotoIndex - 1;
            if (photoToAddIndex == -1) {
                photoToAddIndex = itemsCount - 1;
                bioToAddIndex--;
                bioToAddIndex = bioToAddIndex == -1 ? this._bios.length - 1 : bioToAddIndex;
            }
        }
        this.getCurrentPhoto().css("display", "none");
        this.getCurrentPhoto().css("visibility", "hidden");
        var nextLi = this.getPhotoControl(this._currentBioIndex, nextPhotoIndex);
        nextLi.css("visibility", "");
        nextLi.fadeIn(this._fadeInterval);
        this._currentPhotoIndex = nextPhotoIndex;

        if (this._autoRotateBios && bioToAddIndex != this._currentBioIndex) {
            if (this.getBioControl(bioToAddIndex).length == 0) {
                this.addBio(this._bios[bioToAddIndex], 1, false, forward);
            }
        }
        else if (this.getPhotoControl(this._currentBioIndex, photoToAddIndex).length == 0) {
            this.addPhoto(this.getCurrentBio()._photos[photoToAddIndex], this._currentBioIndex, false);
        }
        if (this._isPlaying) {
            this._timeoutValue = window.setTimeout(this._objectName + '.switchView(true)', this._interval);
        }
        this._disableButtons = false;
    },

    hideCurrentBio: function(forward, stopPlaying) {
        this._disableButtons = true;
        this.getBioControl(this._currentBioIndex).fadeOut(this._fadeInterval);
        setTimeout(this._objectName + '.showNextBio(' + forward + ',' + stopPlaying + ')', this._fadeInterval + this._fadeInDelay);
    },

    showNextBio: function(forward, stopPlaying) {
        //scroll top description
        var divs = $(".descr");
        for (var i = 0; i < divs.length; i++) {
            divs[i].scrollTop = 0;
        }
        var itemsCount = this._bios.length;
        var nextBioIndex = this._currentBioIndex;
        var bioToAddIndex = nextBioIndex;
        var photoToDisplayIndex;
        var photoToAddIndex;
        if (forward) {
            nextBioIndex++;
            nextBioIndex = nextBioIndex == itemsCount ? 0 : nextBioIndex;

            bioToAddIndex = nextBioIndex + 1;
            bioToAddIndex = bioToAddIndex == itemsCount ? 0 : bioToAddIndex;

            photoToDisplayIndex = 0;
            photoToAddIndex = photoToDisplayIndex + 1;
        }
        else {
            nextBioIndex--;
            nextBioIndex = nextBioIndex == -1 ? itemsCount - 1 : nextBioIndex;

            bioToAddIndex = nextBioIndex - 1;
            bioToAddIndex = bioToAddIndex == itemsCount ? 0 : bioToAddIndex;

            photoToDisplayIndex = this._bios[nextBioIndex]._photos.length - 1;
            photoToAddIndex = photoToDisplayIndex - 1;
        }

        $("#bio" + nextBioIndex + " li").hide();
        $("#bio" + nextBioIndex + " li").css(
        {
            zoom: "0",
            visibility: "hidden"
        }); // IE Fix
        var divDescr = this.getBioControl(this._currentBioIndex).find(".descr");
        divDescr.scrollTop = 0;
        this.getBioControl(this._currentBioIndex).hide();
        this.getPhotoControl(nextBioIndex, this._currentPhotoIndex).css("visibility", "hidden");
        this.getPhotoControl(nextBioIndex, this._currentPhotoIndex).hide();
        this.getPhotoControl(nextBioIndex, this._currentPhotoIndex).css(
        {
            zoom: "0"
        }); // IE Fix

        this.getCurrentPhoto().hide();
        this.getCurrentPhoto().css("visibility", "hidden");

        this.getPhotoControl(nextBioIndex, photoToDisplayIndex).css("visibility", "");
        this.getPhotoControl(nextBioIndex, photoToDisplayIndex).show();

        this._currentPhotoIndex = photoToDisplayIndex;

        this.getBioControl(nextBioIndex).fadeIn(this._fadeInterval);
        this._currentBioIndex = nextBioIndex;
        if (this.getCurrentBio()._photos.length == 1) {
            if (this.getBioControl(bioToAddIndex).length == 0) {
                this.addBio(this._bios[bioToAddIndex], 1, false, forward);
            }
        }
        else if (this.getPhotoControl(this._currentBioIndex, photoToAddIndex).length == 0) {
            this.addPhoto(this.getCurrentBio()._photos[photoToAddIndex], this._currentBioIndex, false);
        }
        this._isPlaying = stopPlaying ? false : this._isPlaying;
        if (this._isPlaying) {
            this._timeoutValue = window.setTimeout(this._objectName + '.switchView(true)', this._interval);
        }
        this._disableButtons = false;
    },

    getNextControl: function() {
        return $('#' + this._nextButtonId);
    },
    getPrevControl: function() {
        return $('#' + this._prevButtonId);
    },
    getPausePlayControl: function() {
        return $('#' + this._pausePlayButtonId);
    },
    getPhotoControl: function(bioIndex, photoIndex) {
        return $('#photo' + bioIndex + "_" + photoIndex);
    },
    getBioControl: function(bioIndex) {
        return $('#bio' + bioIndex);
    },
    getCurrentBio: function() {
        return this._bios[this._currentBioIndex];
    },
    getCurrentPhoto: function() {
        return this.getPhotoControl(this._currentBioIndex, this._currentPhotoIndex);
    },

    disablePrevButton: function() {
        this._btnPrevDisabled = true;
        this.getPrevControl().attr("src", player._prevButtonDisabledImageUrl);
    },
    enablePrevButton: function() {
        this._btnPrevDisabled = false;
        this.getPrevControl().attr("src", player._prevButtonImageUrl);
    }
};

function Biography(id, name, description) {
    this._id = id;
    this._name = name;
    this._description = description;
}
Biography.prototype =
{
    _id: null,
    _name: null,
    _description: null,
    _photos: null
}

function Photo(id, path) {
    this._id = id;
    this._path = path;
}
Photo.prototype =
{
    _id: null,
    _path: null
}

function BiographyDao(configFileName) {
    this._configFileName = configFileName;
}
BiographyDao.prototype =
{
    _biographies: null,
    _loadCompleteCallback: null,

    initialize: function(callback) {
        this._loadCompleteCallback = callback;
        $.get(this._configFileName, this.onAjaxSuccess.createDelegate(this));
    },

    onAjaxSuccess: function(xml) {
        var itemsCount = $("li", xml).length;
        var elem = $(xml);
        this._biographies = new Array();
        for (var i = 0; i < itemsCount; i++) {
            var item = $("#bio" + i, elem);
            var biography = new Biography(i, item.find("span").text(), item.find("p").text());
            biography._photos = new Array();
            for (var j = 0; j < $("img", item).length; j++) {
                var img = $($("img", item)[j]);
                biography._photos.push(new Photo(img.attr("id"), img.attr("src")));
            }
            //            $("img", item).each(
            //                          function() {
            //                              biography._photos.push(new Photo(this.id, this.src));
            //                          });
            this._biographies.push(biography);
        }
        this._loadCompleteCallback.call();
    },

    getAll: function() {
        return this._biographies;
    },

    getById: function(id) {
        return this._biographies[id];
    }
}
function PhotosDao() {
    this._id = id;
    this._name = name;
    this._description = description;
}
PhotosDao.prototype =
{
    _photos: null,

    getPhoto: function(biographyId, photoId) {
        var bio = dao.getById(biographyId);
        return bio._photos[photoId];
    }
}