var Viewer = function (_container, _images, _options) {



    ///////////////////////////////////////
    // Déclaration des attributs
    ///////////////////////////////////////
    this.images = null;
    this.imagesCount = 0;
    this.options = {
        ratio : 16 / 9,
        animationSpeed : 400,
        fadeSpeed : 400,
        afterFadeInEvent : null,
        flowplayer : {
            src : "flowplayer.swf",
            options : {
                onFinish : function() {
                    instance.closeVideoMode(function () {
                        // Faire réapparaitre l'image
                        instance.fadeIn(instance.indexCurrentImage);
                    });
                }
            }
        }
    };
    this.indexCurrentImage = null;
    this.timer = null;
    this.mode = "image";
    var instance = this;

    this.viewer = _container;
    this.viewer_push = $("#viewer_push", this.viewer);
    this.viewer_push_video = $("#viewer_push_video", this.viewer);
    this.viewer_push_images = $("#viewer_push_images", this.viewer);
    this.viewer_push_hover = $("#viewer_push_hover", this.container);
    this.viewer_thumbnails = $("#viewer_thumbnails", this.viewer);
    this.viewer_panel = $("#viewer_panel", this.viewer);

    // Configuration css pour les animations
    this.css = {"image" : null, "video" : null};
    this.css.image = {
        "viewer" : {height : this.viewer.height()},
        "viewer_push" : {height : this.viewer_push.height()},
        "viewer_panel" : null
    };
    this.css.video = {
        "viewer" : {height : null},
        "viewer_push" : {height : this.viewer_push.width() / this.options.ratio},
        "viewer_panel" : null
    };

    this.player = null;


    this.isMoving = false;




    //////////////////////////////////////
    // Déclaration des methodes
    //////////////////////////////////////

    this.startMove = function()
    {
        this.isMoving = true;
    }

    this.stopMove = function()
    {
       this.isMoving = false;
    }

    // Creer une image non visible dans un lien et du panel info
    this.createImage = function (index) {
        var image = this.images[index];

        var div = $("<div>")
            .addClass("image")
            .attr("index_image", index);

        var a = $("<a>").attr("href", "#");

        if (image.type == "video") {
            a.click(function () {
                if( !instance.isMoving )
                {
                    instance.startMove();
                    instance.openVideoMode(function () {
                        instance.playVideo(index);
                        instance.stopMove();
                    });
                }
            });
        } else {
            if (typeof(image.info.hrefLink) == 'string' && image.info.hrefLink.length > 0) {
                a.click(function() { 
                    if( !instance.isMoving )
                    {
                        instance.startMove();
                        $(location).attr("href", image.info.hrefLink); 
                        instance.stopMove();
                    }
                });
            }
        }

        a.hover(function () {instance.hoverEvent("in", index);}, function() {instance.hoverEvent("out", index);});

        var img = $("<img>").attr("src", image.srcNormal);
        a.append(img);

        div.append(a);

        var div_info = $("<div>").attr("class", "info").addClass(image.info.styleName);

        if (image.info.title.length > 0 || image.info.credit.length > 0 || image.info.textLink.length > 0) {
            var ul = $("<ul>");
            if (image.info.title.length > 0) {
                ul.append($("<li>").attr("class", "title").html(image.info.title));
            }
            if (typeof(image.info.textLink) == 'string' && image.info.textLink.length > 0) {
                ul.append($("<li>").attr("class", "lien_vue").append($("<a>").attr("href", image.info.hrefLink).html(image.info.textLink)));
            }
            if (image.info.credit.length) {
                ul.append($("<li>").attr("class", "credit").html("Crédit : "+image.info.credit));
            }
            div_info.append(ul);
        } else {
            div_info.css("display", "none");
        }
        div.append(div_info);

        return div;
    }


    // Lancement de la video dans le lecteur
    this.playVideo = function (index) {
        if (this.player != null) this.player.unload();
        this.player.play(this.images[index].srcFlv);
    }

    // Ajouter un lecteur flash au HTML
    this.loadPlayer = function () {
        var config = {src : this.options.flowplayer.src, wmode : 'opaque'};
        this.player = flowplayer("viewer_push_video", config, this.options.flowplayer.options);
    }

    // Ajuste le viewer pour le mode video
    this.openVideoMode = function (callback) {
        this.mode = "video";
        this.stop();
        this.viewer.css(this.css.video.viewer);

        // Fait disparaitre l'image
        $("div[index_image='" + this.indexCurrentImage + "']", this.viewer_push_images).fadeOut(instance.options.fadeSpeed, function() {
            // Anime l'augmentation du push
            instance.viewer_push.animate(instance.css.video.viewer_push, instance.options.animationSpeed);

            // Anime le deplacement du panel
            instance.viewer_panel.animate(instance.css.video.viewer_panel, instance.options.animationSpeed, function () {
                // Le temps que les animations s'execute entierement l'utilisateur à peut être voulu repasser en mode image
                if (instance.mode == "video") {
                    instance.viewer_push_video.show();
                    instance.loadPlayer();
                    if (typeof(callback) == "function") callback();
                }
               // if (instance.mode == "image")  instance.closeVideoMode();
            });

        });
    }


    // Ajuste le viewer pour le mode image
    this.closeVideoMode = function (callback) {
        this.mode = "image";
        if (this.player != null) this.player.stop().unload();

        // Enleve le lecteur flash
        //this.viewer_push_video.hide();
        this.viewer_push_video.empty();

        // Anime la reduction du push
        this.viewer_push.animate(this.css.image.viewer_push, instance.options.animationSpeed);

        // Anime le deplacement des ministures
        instance.viewer_panel.animate(instance.css.image.viewer_panel, instance.options.animationSpeed, function () {
             instance.viewer.css(instance.css.image.viewer);
             if (typeof(callback) == "function") callback();
        });
    }

    // Ajoute une image non visible au container html
    this.loadImage = function (index) {
        var image = this.images[index];
        if (image.loaded == false) {
            this.viewer_push_images.append(this.createImage(index));
            image.loaded = true;
        }
    }

    // Charge la premiere image dans le html et lance le fadeIn
    this.start = function (index) {
        if (this.images.length > 0) {
            if (index == null) index = 0;
            //this.loadImage(index);
            this.fadeIn();
        }
    }

    // Annule le timer programmé
    this.stop = function () {
        clearTimeout(this.timer);
        this.timer = null;
    }

    // Retourne l'indice suivant l'indice de l'image courante ou de l'indice donné en parametre
    this.getIndiceNextImage = function (index) {
        if (index == null) {
            if (this.indexCurrentImage == null) return 0;
            else index = this.indexCurrentImage;
        }

        if (this.imagesCount > index + 1) index += 1;
        else index = 0;

        return index;
    }

    // Fait l'effet de transition entre les 2 images
    this.transition = function (index) {
        this.stop();
        if (this.mode == "video") {
            this.closeVideoMode(
                function () {
                    instance.transition(index);
                });
        } else {
            this.fadeOut();
            this.fadeIn(index);
        }
    }


    // Fait apparait une image en augmentant l'opacité
    // A la fin de l'effet on relance une transition avec un timer
    this.fadeIn = function (index) {
        if( ! this.isMoving )
        {
            this.startMove();
            if (index == null) index = this.getIndiceNextImage();
            else {
                index = parseInt(index);
                //this.loadImage(index);
            }

            $("div[index_image='" + index + "']", this.viewer_push_images).fadeIn(
                this.options.fadeSpeed,
                function() {
                    instance.indexCurrentImage = index;
                    //instance.loadImage(instance.getIndiceNextImage());
                    // Timer pour relancer une transition
                    instance.timer = setTimeout(function() { if (instance.mode != 'video') instance.transition(); }, instance.images[instance.indexCurrentImage].showTime);
                    instance.viewChangeEvent(instance.indexCurrentImage);
                    // Préchargement de l'image affiché dans la prochaine transition
                    if (typeof(instance.options.afterFadeInEvent) == "function") instance.options.afterFadeInEvent(instance.indexCurrentImage);
                });
            this.stopMove();
        }
    }

    // Fait disparaitre une image en diminuant l'opacité
    this.fadeOut = function () {
        $("div[index_image='" + this.indexCurrentImage + "']", this.viewer_push_images).fadeOut(this.options.fadeSpeed);
    }

    // Sur le clic d'une miniature, lancement d'une transition
    this.thumbnailClick = function () {
        var index = $(this).attr("thumbnail");
        instance.transition(index);
        return false;
    }

    // Ajout de la classe selected à la miniature en cours
    this.viewChangeEvent = function(currentIndex) {
        var thumbnails = $(".thumbnail", this.viewer_thumbnails);
        $("a.selected", thumbnails).removeClass("selected");
        $("a[thumbnail=" + currentIndex + "]", thumbnails).addClass("selected");
    }

    // Création du html des miniatures
    this.loadThumbnails = function () {
        for(var i in this.images) {
            var view = this.images[i];

            var img = $("<img>")
                .attr("src", view.srcThumbnail);

            var a = $("<a>")
                .attr("href", "#")
                .click(this.thumbnailClick)
                .attr("thumbnail", i)
                .append(img);

            var div = $("<div>").addClass("thumbnail").append(a);

            this.viewer_thumbnails.append(div);
        }
        var thumbnails = $(".thumbnail", this.viewer_thumbnails);
        thumbnails.first().addClass("first");
        thumbnails.last().addClass("last");
    }

    this.hoverEvent = function (InOrOut, index) {
        if (this.mode == "image") {
            if (InOrOut == "in") this.stop();
            else this.timer = setTimeout(function () {instance.transition();}, 1000);
        }
    }



    //////////////////////////////////
    // Initialisation
    //////////////////////////////////
    this.options = $.extend(true, this.options, _options);

    // Aucune image n'est chargé
    for(var i in _images) {
        _images[i].loaded = false;
        this.imagesCount++;
    }
    this.images = _images;

    this.viewer_push_images.empty();
    this.loadThumbnails();
    for(var i in this.images) this.loadImage(i);

    /*if ($.browser.msie) {
        this.css.image.viewer_panel = {marginTop : this.viewer_panel.css("margin-top")};
        this.css.video.viewer_panel = {marginTop : 20};
        this.css.video.viewer.height = Math.ceil(this.css.video.viewer_push.height + this.viewer_panel.height() + this.css.video.viewer_panel.marginTop);
    } else {*/
        this.css.image.viewer_panel = {top : this.viewer_panel.css("top")};
        this.css.video.viewer_panel = {top : 20};
        this.css.video.viewer.height = Math.ceil(this.css.video.viewer_push.height + this.viewer_panel.height() + this.css.video.viewer_panel.top);
    //}

    
}
