﻿/* ivm.js -- Image View Manager 0.05  Copyright (C) 2008  Engine Room Co., LTD. */


////////////////////////////////////////////////////////////////////////////////
//
//  修正履歴
//
//  日付        版      編集    備考
//  ------------------------------------------------------------
//  2008/06/13  0.00    Kaigo   開発開始
//  2008/06/17  0.01    Kaigo   一次バージョン完成
//  2008/06/18  0.02    Kaigo   メイン画像読み込みの部分を修正
//
//      キャッシュを使うようにした。
//      キャッシュ読み込み後にサイズを判定するようにしたので、
//      HTMLソース側のサムネイルで「ivm:width="100"」や
//      「ivm:height="100"」と言った指定は、しなくても良くなった。
//
//  2008/06/20  0.03    Kaigo   ウェイト画像の追加とキャッシュの変更
//
//      読み込みが遅い時に、ウェイト画像を表示するように変更した。
//      サムネイルごとにキャッシュを持つような感じになっていたため、
//      読み込み中に次々にサムネイルを移動すると何重にも
//      キャッシュ読み込みが発生していたので、キャッシュをひとつにした。
//      ただ、このあたりはブラウザによって少し挙動が違うようだ。
//
//  2008/07/26  0.04    Kaigo   ライトボックスの背景サイズの計算を修正
//
//      <HTML>要素のscrollWidthとscrollHeightは、どのブラウザでもあるようだ。
//      場合分けせずにscrollWidthとscrollHeightを使うことにした。
//      Operaで不具合あり→<HTML>要素のサイズが変わってしまう。
//
//  2008/07/28  0.05    Kaigo   プロパティボックスのスタイルを調整
//
//      文字を黒色、背景を白色にして半透過にした。
//      表示するテキストがない時は表示しないことにした。
//


////////////////////////////////////////////////////////////////////////////////
//
//  概要：
//      ImageViewManagerクラスの新しいインスタンスを初期化します。
//  引数：
//      owner_element
//          ライト・ボックスで表示するサムネイルを含む要素を指定します。
//
function ImageViewManager(owner_element) {


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      スタイル・オブジェクトを取得します。
    //  引数：
    //      element
    //          スタイルを取得する要素を指定します。
    //  戻り値：
    //      指定された要素のスタイル・オブジェクトを返します。
    //
    function get_style(element) {
        return element.style || element;
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      サムネイルを管理するための内部クラスivm_objectの新しいインスタンスを初期化します。
    //      １個のインスタンスが１個のサムネイルに対応します。
    //  引数：
    //      a
    //          呼び出し元サムネイルの<A>要素
    //      img
    //          呼び出し元サムネイルの<IMG>要素
    //
    function ivm_object(a, img) {


        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      呼びたし元の<A>要素のonclickイベントを処理します。
        //  戻り値：
        //      falseを返します。
        //
        function orig_onclick() {
            show_light_box();
            set_index(index_of(instance));
            return false;

            //  instanceはこのクラスのインスタンスのこと。
            //  イベントハンドラではthisは<A>要素を指す。
        }


        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      ライト・ボックス内に生成されたサムネイル（<A>要素）のonlickイベントを処理します。
        //  戻り値：
        //      falseを返します。
        //
        function thumb_onlcick() {
//  2008/06/18 [S] Kaigo
//            show_in_main_image();
//            set_index(index_of(instance));
            set_index(index_of(instance));
            show_in_main_image();
//  2008/06/18 [E] Kaigo
            return false;

            //  instanceはこのクラスのインスタンスのこと。
            //  イベントハンドラではthisは<A>要素を指す。
        }

//
//  2008/06/18 [S] Kaigo
        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      キャッシュ画像のonloadイベントを処理します。
        //
        function cache_onload() {
//  2008/06/20 [S] Kaigo
            //show_cache(cache.width, cache.height, alt);
            show_cache(main.image.cache.width, main.image.cache.height, alt);
//  2008/06/20 [E] Kaigo
        }

        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      キャッシュ画像のonabortイベントを処理します。
        //
        function cache_onabort() {
            show_cache(128, 96, "画像の読み込みが中断されました。");
        }

        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      キャッシュ画像のonerrorイベントを処理します。
        //
        function cache_onerror() {
            show_cache(128, 96, "エラーが発生しました。");
        }

        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      キャッシュ画像をメイン画像に表示し、キャッシュをクリアします。
        //  引数：
        //      _width
        //          希望する幅を指定します。
        //          ただし、呼び出し元要素のivm:width属性が優先されます。
        //      _height
        //          希望する高さを指定します。
        //          ただし、呼び出し元要素のivm:height属性が優先されます。
        //      _msg
        //          プロパティ・ボックスに表示するテキストを指定します。
        //
        function show_cache(_width, _height, _msg) {
            if (index_of(instance) == current_index) {
                _width = width ? parseInt(width) : _width;
                _height = height ? parseInt(height) : _height;


                main.image.style.display = "none"; // 変更を加えている最中は非表示にする
                main.image.element.setAttribute("src", "");


                //  属性の設定

                main.image.element.setAttribute("alt", alt);
                main.image.element.setAttribute("src", src);
                main.image.element.setAttribute("width", _width);
                main.image.element.setAttribute("height", _height);


                //  メイン画像の位置を補正

                main.image.style.left = ((light.box.width - _width) / 2) + "px";
                main.image.style.top = ((light.box.height - thumb.box.height - _height) / 2) + "px";

//  2008/06/20 [S] Kaigo
                light.box.style.backgroundImage = "";
//  2008/06/20 [E] Kaigo

                main.image.style.display = "inline"; // 変更が終わったら表示する

                //  プロパティを表示

                // 2008/07/28 [S] Kaigo
                //if (is_msie) {
                //    property.box.element.innerText = _msg;
                //} else {
                //    property.box.element.textContent = _msg;
                //}
                if (is_msie) {
                    property.box.style.display = (property.box.element.innerText = _msg) ? "block" : "none";
                } else {
                    property.box.style.display = (property.box.element.textContent = _msg) ? "block" : "none";
                }
                // 2008/07/25 [E] Kaigo
            }


            //  キャッシュをクリア

//  2008/06/20 [S] Kaigo
//            cache.onload = null;
//            cache.onabort = null;
//            cache.onerror = null;
//            cache.src = null;
//            cache = null;
            main.image.cache.onload = null;
            main.image.cache.onabort = null;
            main.image.cache.onerror = null;
//  2008/06/20 [E] Kaigo
        }
//  2008/06/18 [E] Kaigo

//  2008/06/20 [S] Kaigo
        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      ウェイト画像を表示します。
        //
        function show_wait() {
            if (main.image.cache.complete) {
                return;
            }

            if (wait.cache.complete) {
                main.image.style.display = "none";
                light.box.style.backgroundRepeat = "no-repeat";
                light.box.style.backgroundPosition = Math.floor((light.box.width - wait.cache.width) / 2) + "px " +
                    Math.floor((light.box.height - thumb.box.height - wait.cache.height) / 2) + "px";
                light.box.style.backgroundImage = "url(" + wait.src + ")";
            }
        }
// 2008/06/20 [E] Kaigo


        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      呼び出し元の<IMG>要素の属性の値を取得します。
        //  引数：
        //      attribute_name
        //          取得する値に対応した属性の名称を指定します。
        //  戻り値：
        //      取得した属性の値を返します。
        //
        function get_img_attribute(attribute_name) {
            return img.getAttribute(attribute_name) || "";
        }


        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      呼び出し元の<A>要素の属性の値を取得します。
        //  引数：
        //      attribute_name
        //          取得する値に対応した属性の名称を指定します。
        //  戻り値：
        //      取得した属性の値を返します。
        //
        function get_a_attribute(attribute_name) {
            return a.getAttribute(attribute_name) || "";
        }


        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      サムネイルを複製（ライト・ボックス内に配置する<A>要素を生成）します。
        //  戻り値：
        //      複製されたサムネイルの要素（<A>要素）
        //
        function duplicate_thumb() {
            //  <IMG>要素の生成とスタイル
            thumb_element = doc.createElement("img");
            thumb_style = get_style(thumb_element);
            thumb_style.border = "2px solid white";
            thumb_style.verticalAlign = "middle";

            // ４つの属性をコピー

            var attribute_names = ["alt", "src", "height", "width"];

            for (var i = 0; i < attribute_names.length; i++) {
                var attribute_name = attribute_names[i];
                var attribute_value = get_img_attribute(attribute_name);
                thumb_element.setAttribute(attribute_name, attribute_value);
            }

            // <A>要素

            var proxy_element = doc.createElement("a");
            proxy_element.href = "javascript:void(0)";
            proxy_element.appendChild(thumb_element);
            proxy_element.onclick = thumb_onlcick;

            return proxy_element;
        }


        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      メイン画像を表示します。
        //
        function show_in_main_image() {
            //  マーカーを表示

            thumb_style.borderColor = "darkseagreen";

//  2008/06/18 [S] Kaigo
//            //  属性の設定
//
//            main.image.element.setAttribute("alt", alt);
//            main.image.element.setAttribute("src", src);
//            main.image.element.setAttribute("width", width);
//            main.image.element.setAttribute("height", height);
//
//
//            //  メイン画像の位置を補正
//
//            main.image.style.left = ((light.box.width - parseInt(width)) / 2) + "px";
//            main.image.style.top = ((light.box.height - thumb.box.height - parseInt(height)) / 2) + "px";
//
//
//            //  プロパティを表示
//
//            if (is_msie) {
//                property.box.element.innerText = alt;
//            } else {
//                property.box.element.textContent = alt;
//            }


            //  キャッシュへ読み込み

//  2008/06/20 [S] Kaigo
//            cache = new Image();
//            cache.onload = cache_onload;
//            cache.onabort = cache_onabort;
//            cache.onerror = cache_onerror;
//            cache.src = src;
            main.image.cache.onload = null;     //  一旦イベントハンドラを外して
            main.image.cache.onabort = null;    //  キャッシュをクリアする。
            main.image.cache.onerror = null;
            main.image.cache.src = "";

            main.image.cache.onload = cache_onload;
            main.image.cache.onabort = cache_onabort;
            main.image.cache.onerror = cache_onerror;
            main.image.cache.src = src;

            setTimeout(show_wait, 500);
//  2008/06/20 [E] Kaigo
//  2008/06/18 [E] Kaigo


            //  スクロールを開始（50ミリ秒後）

            clear_interval();
            timer_id = setInterval(scroll_thumb, 50);
        }


        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      マーカーを非表示にします。
        function inactive() {
            thumb_style.borderColor = "white";
        }


        ////////////////////////////////////////////////////////////////////////////////
        //
        //  概要：
        //      サムネイルのスクロールのアニメーションを処理します。
        //      このメソッドはタイマー・イベントハンドラです。
        //
        function scroll_thumb() {
            //  現在位置
            var old_position = thumb.box.element.scrollLeft;

            //  目標位置
            var target_position = thumb_element.offsetLeft - (thumb.box.element.offsetWidth - thumb_element.offsetWidth) / 2;

            //  次の位置（半分に縮める）
            var new_position = Math.floor((old_position + target_position) / 2);

            thumb.box.element.scrollLeft = new_position;

            if (thumb.box.element.scrollLeft == old_position) {
                //  スクロール位置が動いていなければアニメーション終了
                clear_interval();
            }
        }

        var instance = this;        //  これ
        var thumb_element = null;   //  <IMG>
        var thumb_style = null;     //  <IMG>スタイル

        //  属性の読み取り

        var alt = get_img_attribute("alt");
        var src = get_a_attribute("href");
        var width = get_a_attribute("ivm:width");
        var height = get_a_attribute("ivm:height");
        var cache = null;

        //  イベントハンドラをセット

        a.onclick = orig_onclick;


        //  外部からの呼出し用メソッド

        this.duplicateThumb = duplicate_thumb;
        this.showInMainImage = show_in_main_image;
        this.setInactive = inactive;
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      初期化処理を行います。
    //
    //      既定値の調整・カスタム属性の読み取り・サムネイルの読み取りを行います。
    //
    function init() {
        //  このivm.jsのURLからボタン画像の位置を反映させる。

        var scripts = doc.getElementsByTagName("script");

        for (var i = 0; i < scripts.length; i++) {
            var script = scripts[i];

            if (script.src.match(/\/?ivm\.js$/i)) {
                var src_url = script.src;
                src_url = src_url.substring(0, src_url.lastIndexOf("/") + 1);

                buttons.close.src = src_url + buttons.close.src;
                buttons.index.prev.src = src_url + buttons.index.prev.src;
                buttons.index.next.src = src_url + buttons.index.next.src;
                buttons.thumb.left.src = src_url + buttons.thumb.left.src;
                buttons.thumb.right.src = src_url + buttons.thumb.right.src;
                wait.src = src_url + wait.src;
                break;
            }
        }


        //  属性の読み取り

        var attribute = null;

        if (attribute = owner_element.getAttribute("ivm:width")) {
            light.box.width = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:height")) {
            light.box.height = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:padding_left")) {
            light.box.padding.left = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:padding_top")) {
            light.box.padding.top = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:padding_right")) {
            light.box.padding.right = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:padding_bottom")) {
            light.box.padding.bottom = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:thumb_height")) {
            thumb.box.height = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:close_alt")) {
            buttons.close.alt = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:close_src")) {
            buttons.close.src = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:close_width")) {
            buttons.close.width = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:close_height")) {
            buttons.close.height = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:prev_alt")) {
            buttons.index.prev.alt = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:prev_src")) {
            buttons.index.prev.src = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:prev_width")) {
            buttons.index.prev.width = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:prev_height")) {
            buttons.index.prev.height = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:next_alt")) {
            buttons.index.next.alt = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:next_src")) {
            buttons.index.next.src = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:next_width")) {
            buttons.index.next.width = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:next_height")) {
            buttons.index.next.height = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:left_alt")) {
            buttons.thumb.left.alt = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:left_src")) {
            buttons.thumb.left.src = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:left_width")) {
            buttons.thumb.left.width = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:left_height")) {
            buttons.thumb.left.height = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:right_alt")) {
            buttons.thumb.right.alt = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:right_src")) {
            buttons.thumb.right.src = attribute;
        }

        if (attribute = owner_element.getAttribute("ivm:right_width")) {
            buttons.thumb.right.width = parseInt(attribute);
        }

        if (attribute = owner_element.getAttribute("ivm:right_height")) {
            buttons.thumb.right.height = parseInt(attribute);
        }

        // 2008/06/20 [S] Kaigo
        if (attribute = owner_element.getAttribute("ivm:wait_src")) {
            wait.src = attribute;
        }


        // 画像キャッシュ用
        main.image.cache = new Image();

        wait.cache = new Image();
        wait.cache.src = wait.src;
        // 2008/06/20 [E] Kaigo


        //  サムネイルの読み取り：owner_elementの直下の<a><img /></a>という構造をサムネイルと認識する。

        for (var a = owner_element.firstChild; a; a = a.nextSibling) {
            if (a.tagName != "A") {
                continue;
            }

            for (var img = a.firstChild; img; img = img.nextSibling) {
                if (img.tagName != "IMG") {
                    continue;
                }

                child_objects.push(new ivm_object(a, img));
            }
        }

    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      ライト・ボックスを表示します。
    //
    function show_light_box() {
        if (!light.back.element) {
            //  ライト・ボックスが作成されていないとき（初回）は作成する。

            var img_element;
            var img_style;


            // light.back

            light.back.element = doc.createElement("div");
            light.back.style = get_style(light.back.element);
            light.back.style.position = "absolute";
            light.back.style.left = "0px";
            light.back.style.top = "0px";
            light.back.style.background = "black";
            light.back.element.onclick = hide_light_box;
            body.element.appendChild(light.back.element);

            if (is_msie) {
                // IEではfilterを使う。
                light.back.style.filter = "alpha(opacity=75)";
            } else {
                // Firefox, Safariではopacityを使う。
                light.back.style.opacity = "0.75";
            }


            // light.box

            light.box.element = doc.createElement("div");
            light.box.style = get_style(light.box.element);
            light.box.style.position = "absolute";
            light.box.style.width = light.box.width + "px";
            light.box.style.height = light.box.height + "px";
            light.box.style.display = "none";
            light.box.style.background = "white";
            light.box.style.textAlign = "left";
            body.element.appendChild(light.box.element);


            // main.image

            main.image.element = doc.createElement("img");
            main.image.style = get_style(main.image.element);
            main.image.style.position = "absolute";
            main.image.style.display = "none";
            light.box.element.appendChild(main.image.element);


            // thumb.box

            thumb.box.width = light.box.width - light.box.padding.left - light.box.padding.right -
                buttons.thumb.left.width - buttons.thumb.right.width;

            thumb.box.element = doc.createElement("div");
            thumb.box.style = get_style(thumb.box.element);
            thumb.box.style.position = "absolute";
            thumb.box.style.left = (light.box.padding.left + buttons.thumb.left.width) + "px";
            thumb.box.style.top = (light.box.height - thumb.box.height - light.box.padding.bottom) + "px";
            thumb.box.style.width = thumb.box.width + "px";
            thumb.box.style.height = thumb.box.height + "px";
            thumb.box.style.background = "white";
            thumb.box.style.overflow = "hidden";
            thumb.box.style.whiteSpace = "nowrap";
            thumb.box.style.display = "none";
            light.box.element.appendChild(thumb.box.element);


            // thumbnails

            for (var i = 0; i < child_objects.length; i++) {
                var child_object = child_objects[i];
                thumb.box.element.appendChild(child_object.duplicateThumb());
            }


            // property.box

            property.box.element = doc.createElement("div");
            property.box.style = get_style(property.box.element);
            property.box.style.position = "absolute";
            property.box.style.left = light.box.padding.left + "px";
            property.box.style.top = light.box.padding.top + "px";
            // 2008/07/28 [S] Kaigo
            property.box.style.color = property.box.foreground;
            property.box.style.background = property.box.background;
            property.box.style.padding = property.box.padding.top + "px " + property.box.padding.right + "px " + property.box.padding.bottom + "px " + property.box.padding.left + "px";
            if (is_msie) {
                // IEではfilterを使う。
                property.box.style.filter = "alpha(opacity=50)";
            } else {
                // Firefox, Safariではopacityを使う。
                property.box.style.opacity = "0.5";
            }
            // 2008/07/28 [E] Kaigo
            property.box.style.display = "none";
            light.box.element.appendChild(property.box.element);


            // buttons.close

            buttons.close.element = doc.createElement("a");
            buttons.close.style = get_style(buttons.close.element);
            buttons.close.element.setAttribute("href", "javascript:void(0)");
            buttons.close.style.position = "absolute";
            buttons.close.style.top = light.box.padding.top + "px";
            buttons.close.style.left = (light.box.width - light.box.padding.right - buttons.close.width) + "px";
            buttons.close.style.display = "none";
            buttons.close.element.onclick = hide_light_box;
            light.box.element.appendChild(buttons.close.element);

            img_element = doc.createElement("img");
            img_style = get_style(img_element);
            img_element.setAttribute("alt", buttons.close.alt);
            img_element.setAttribute("src", buttons.close.src);
            img_element.setAttribute("width", buttons.close.width);
            img_element.setAttribute("height", buttons.close.height);
            img_style.border = "none";
            buttons.close.element.appendChild(img_element);


            // buttons.index.prev

            buttons.index.prev.element = doc.createElement("a");
            buttons.index.prev.style = get_style(buttons.index.prev.element);
            buttons.index.prev.element.setAttribute("href", "javascript:void(0)");
            buttons.index.prev.style.position = "absolute";
            buttons.index.prev.style.top = Math.floor(light.box.padding.top +
                (light.box.height - thumb.box.height - buttons.index.prev.height -
                light.box.padding.top - light.box.padding.bottom) / 2) + "px";
            buttons.index.prev.style.left = light.box.padding.left + "px";
            buttons.index.prev.style.display = "none";
            buttons.index.prev.element.onclick = prev_index;
            light.box.element.appendChild(buttons.index.prev.element);

            img_element = doc.createElement("img");
            img_style = get_style(img_element);
            img_element.setAttribute("alt", buttons.index.prev.alt);
            img_element.setAttribute("src", buttons.index.prev.src);
            img_element.setAttribute("width", buttons.index.prev.width);
            img_element.setAttribute("height", buttons.index.prev.height);
            img_style.border = "none";
            buttons.index.prev.element.appendChild(img_element);


            // buttons.index.next

            buttons.index.next.element = doc.createElement("a");
            buttons.index.next.style = get_style(buttons.index.next.element);
            buttons.index.next.element.setAttribute("href", "javascript:void(0)");
            buttons.index.next.style.position = "absolute";
            buttons.index.next.style.top = Math.floor(light.box.padding.top +
                (light.box.height - thumb.box.height - buttons.index.next.height -
                light.box.padding.top - light.box.padding.bottom) / 2) + "px";
            buttons.index.next.style.left = (light.box.width - buttons.index.next.width -
                light.box.padding.right) + "px";
            buttons.index.next.style.display = "none";
            buttons.index.next.element.onclick = next_index;
            light.box.element.appendChild(buttons.index.next.element);

            img_element = doc.createElement("img");
            img_style = get_style(img_element);
            img_element.setAttribute("alt", buttons.index.next.alt);
            img_element.setAttribute("src", buttons.index.next.src);
            img_element.setAttribute("width", buttons.index.next.width);
            img_element.setAttribute("height", buttons.index.next.height);
            img_style.border = "none";
            buttons.index.next.element.appendChild(img_element);


            // buttons.thumb.left

            buttons.thumb.left.element = doc.createElement("a");
            buttons.thumb.left.style = get_style(buttons.thumb.left.element);
            buttons.thumb.left.element.setAttribute("href", "javascript:void(0)");
            buttons.thumb.left.style.position = "absolute";
            buttons.thumb.left.style.top = Math.floor(light.box.height - light.box.padding.bottom -
                (thumb.box.height + buttons.thumb.left.height) / 2) + "px";
            buttons.thumb.left.style.left = light.box.padding.left + "px";
            buttons.thumb.left.style.display = "none";
            buttons.thumb.left.element.onmouseover = thumb_left_start;
            buttons.thumb.left.element.onmouseout = clear_interval;
            light.box.element.appendChild(buttons.thumb.left.element);

            img_element = doc.createElement("img");
            img_style = get_style(img_element);
            img_element.setAttribute("alt", buttons.thumb.left.alt);
            img_element.setAttribute("src", buttons.thumb.left.src);
            img_element.setAttribute("width", buttons.thumb.left.width);
            img_element.setAttribute("height", buttons.thumb.left.height);
            img_style.border = "none";
            buttons.thumb.left.element.appendChild(img_element);


            // buttons.thumb.right

            buttons.thumb.right.element = doc.createElement("a");
            buttons.thumb.right.style = get_style(buttons.thumb.right.element);
            buttons.thumb.right.element.setAttribute("href", "javascript:void(0)");
            buttons.thumb.right.style.position = "absolute";
            buttons.thumb.right.style.top = Math.floor(light.box.height - light.box.padding.bottom -
                (thumb.box.height + buttons.thumb.right.height) / 2) + "px";
            buttons.thumb.right.style.left = (light.box.width - buttons.thumb.right.width -
                light.box.padding.right) + "px";
            buttons.thumb.right.style.display = "none";
            buttons.thumb.right.element.onmouseover = thumb_right_start;
            buttons.thumb.right.element.onmouseout = clear_interval;
            light.box.element.appendChild(buttons.thumb.right.element);

            img_element = doc.createElement("img");
            img_style = get_style(img_element);
            img_element.setAttribute("alt", buttons.thumb.right.alt);
            img_element.setAttribute("src", buttons.thumb.right.src);
            img_element.setAttribute("width", buttons.thumb.right.width);
            img_element.setAttribute("height", buttons.thumb.right.height);
            img_style.border = "none";
            buttons.thumb.right.element.appendChild(img_element);
        }

        light.back.style.width = "0px";
        light.back.style.height = "0px";
        light.back.style.display = "block";

        light.box.style.top = (scroll_base.scrollTop + Math.floor((html.element.clientHeight - 1) / 2)) + "px";
        light.box.style.width = "1px";
        light.box.style.height = "1px";
        light.box.style.display = "block";

        main.image.element.setAttribute("width", "0");
        main.image.element.setAttribute("height", "0");

        set_light_back();

        clear_interval();
        timer_id = setInterval(show_continue, 50);
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      背景のサイズを設定します。
    //
    function set_light_back() {
        var scrollWidth;
        var scrollHeight;

        // 2008/07/26 [S] Kaigo
        //if (is_msie) {
        //    scrollWidth = html.element.scrollWidth;
        //    scrollHeight = html.element.scrollHeight;
        //} else {
        //    scrollWidth = html.element.offsetWidth;
        //    scrollHeight = html.element.offsetHeight;
        //}
        scrollWidth = html.element.scrollWidth;
        scrollHeight = html.element.scrollHeight;
        // 2008/07/26 [E] Kaigo

        var clientWidth = html.element.clientWidth;
        var clientHeight = html.element.clientHeight;

        light.back.style.width = ((scrollWidth > clientWidth) ? scrollWidth : clientWidth) + "px";
        light.back.style.height = ((scrollHeight > clientHeight) ? scrollHeight : clientHeight) + "px";
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      ライト・ボックスの位置を補正します。
    //
    function relocate() {
        set_light_back();

        light.box.style.left = (scroll_base.scrollLeft + Math.floor((html.element.clientWidth - light.box.width) / 2)) + "px";
        light.box.style.top = (scroll_base.scrollTop + Math.floor((html.element.clientHeight - light.box.height) / 2)) + "px";
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      ライト・ボックス表示のアニメーションを処理します。
    //
    //      このメソッドはタイマー・イベントハンドラです。
    //
    function show_continue() {

        //  水平に線を伸ばす。

        var offset_width = light.box.element.offsetWidth;

        if (offset_width < light.box.width) {
            var next_width = Math.floor((offset_width + light.box.width + 1) / 2);
            light.box.style.width = next_width + "px";
            light.box.style.left = (scroll_base.scrollLeft + Math.floor((html.element.clientWidth - next_width) / 2)) + "px";
            return;
        }


        //  垂直方向に広げる。

        var offset_height = light.box.element.offsetHeight;

        if (offset_height < light.box.height) {
            var next_height = Math.floor((offset_height + light.box.height + 1) / 2);
            light.box.style.top = (scroll_base.scrollTop + Math.floor((html.element.clientHeight - next_height) / 2)) + "px";
            light.box.style.height = next_height + "px";
            return;
        }

        clear_interval();


        //  位置と大きさを正確なものにする。（relocate()を参照）

        light.box.style.left = (scroll_base.scrollLeft + Math.floor((html.element.clientWidth - light.box.width) / 2)) + "px";
        light.box.style.top = (scroll_base.scrollTop + Math.floor((html.element.clientHeight - light.box.height) / 2)) + "px";
        light.box.style.width = light.box.width + "px";
        light.box.style.height = light.box.height + "px";


        //  各要素を表示

        main.image.style.display = "inline";
        thumb.box.style.display = "block";
        property.box.style.display = "block";
        //buttons.close.style.display = "inline";       // ３つのボタンはthumb.box.element.onmousemoveで表示される。
        //buttons.index.prev.style.display = "inline";
        //buttons.index.next.style.display = "inline";
        buttons.thumb.left.style.display = "inline";
        buttons.thumb.right.style.display = "inline";

        //thumb.box.element.scrollLeft = 0;


        //  メイン画像への表示

        if ((current_index >= 0) && (current_index < child_objects.length)) {
            child_objects[current_index].showInMainImage();
        }


        //  各イベントハンドラをセット

        window.onscroll = relocate;
        window.onresize = relocate;
        html.element.onkeydown = html_onkeydown;
        light.back.element.onmouseover = light_back_onmouseover;
        light.box.element.onmousemove = light_box_onmousemove;
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      キーボード入力を処理します。
    //  戻り値：
    //      処理されたときにfalseを、それ以外はundefinedを返します。
    //
    function html_onkeydown() {
        var e = window.event || arguments[0];

        switch (e.keyCode) {
        case 0x1b:  //  [ESC]キー
            hide_light_box();
            return false;

        case 0x25:  //  左矢印キー
            prev_index();
            return false;

        case 0x27:  //  右矢印キー
            next_index();
            return false;
        }
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      背景要素のマウスオーバー・イベントを処理します。
    //
    function light_back_onmouseover() {
        //  ３つのボタンを非表示にする。
        buttons.close.visible = false;
        buttons.close.style.display = "none";
        buttons.index.prev.visible = false;
        buttons.index.prev.style.display = "none";
        buttons.index.next.visible = false;
        buttons.index.next.style.display = "none";
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      ライト・ボックスのマウスムーブ・イベントを処理します。
    //
    function light_box_onmousemove() {
        //  「閉じる」ボタンを表示
        if (!buttons.close.visible) {
            buttons.close.visible = true;
            buttons.close.style.display = "inline";
        }

        //  マウスポインタの水平位置の計算
        var x = is_msie ? event.x : arguments[0].clientX;
        x += scroll_base.scrollLeft - light.box.element.offsetLeft;

        if (x < light.box.element.offsetWidth / 2) {
            //  左側

            if (!buttons.index.prev.visible) {
                buttons.index.prev.visible = true;
                buttons.index.prev.style.display = "inline";
            }

            if (buttons.index.next.visible) {
                buttons.index.next.visible = false;
                buttons.index.next.style.display = "none";
            }
        } else {
            //  右側

            if (!buttons.index.next.visible) {
                buttons.index.next.visible = true;
                buttons.index.next.style.display = "inline";
            }

            if (buttons.index.prev.visible) {
                buttons.index.prev.visible = false;
                buttons.index.prev.style.display = "none";
            }
        }
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      ライト・ボックスを閉じます。
    //
    function hide_light_box() {
        //  各要素を非表示にする。

        main.image.style.display = "none";
        thumb.box.style.display = "none";
        property.box.style.display = "none";
        buttons.close.visible = false;
        buttons.close.style.display = "none";
        buttons.index.prev.visible = false;
        buttons.index.prev.style.display = "none";
        buttons.index.next.visible = false;
        buttons.index.next.style.display = "none";
        buttons.thumb.left.style.display = "none";
        buttons.thumb.right.style.display = "none";


        //  各イベントハンドラを外す

        window.onscroll = null;
        window.onresize = null;
        html.element.onkeydown = null;
        light.back.element.onmouseover = null;
        light.box.element.onmousemove = null;

        clear_interval();
        timer_id = setInterval(hide_continue, 50);
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      ライト・ボックス非表示のアニメーションを処理します。
    //
    //      このメソッドはタイマー・イベントハンドラです。
    //
    function hide_continue() {
        //  垂直方向に縮める。

        var offset_height = light.box.element.offsetHeight;

        if (offset_height > 1) {
            var next_height = Math.floor(offset_height / 2);

            if (next_height < 1) {
                next_height = 1;
            }

            light.box.style.top = (scroll_base.scrollTop + Math.floor((html.element.clientHeight - next_height) / 2)) + "px";
            light.box.style.height = next_height + "px";
            return;
        }


        //  ライト・ボックスを非表示にする。

        if (light.box.style.display != "none") {
            light.box.style.display = "none";
            return;
        }

        clear_interval();


        //  背景を非表示にする。

        light.back.style.display = "none";
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      子オブジェクトのインデックスを検索します。
    //  引数：
    //      インデックスを検索する子オブジェクトを指定します。
    //  戻り値：
    //      子オブジェクトのインデックスを返します。見つからなかった場合は-1を返します。
    function index_of(child_object) {
        for (var i = 0; i < child_objects.length; i++) {
            if (child_objects[i] == child_object) {
                return i;
            }
        }

        return -1;
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      現在のインデックスを設定します。
    //      メイン画像への表示はしません。
    //  引数：
    //      index
    //          設定する子オブジェクトのインデックスを指定します。
    //  戻り値：
    //      新しいインデックスを設定できた時にtrueを、そうでない時にfalseを返します。
    //
    function set_index(index) {
        if (current_index == index) {
            return false;
        }

        if (index < 0) {
            return false;
        }

        if (index >= child_objects.length) {
            return false;
        }

        if ((current_index >= 0) && (current_index < child_objects.length)) {
            child_objects[current_index].setInactive();
        }

        current_index = index;
        return true;
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      前のインデックス位置の画像を表示します。
    //
    function prev_index() {
        if (set_index(current_index - 1)) {
            child_objects[current_index].showInMainImage();
        }
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      次のインデックス位置の画像を表示します。
    //
    function next_index() {
        if (set_index(current_index + 1)) {
            child_objects[current_index].showInMainImage();
        }
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      サムネイルの右スクロールを開始します。
    //
    function thumb_right_start() {
        clear_interval();
        timer_id = setInterval(thumb_right, 5);
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      サムネイルの左スクロールを開始します。
    //
    function thumb_left_start() {
        clear_interval();
        timer_id = setInterval(thumb_left, 5);
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      サムネイルを右スクロールします。
    //
    //      このメソッドはタイマー・イベントハンドラです。
    //
    function thumb_right() {
        var old_position = thumb.box.element.scrollLeft;

        thumb.box.element.scrollLeft = old_position + 1;
        
        if (thumb.box.element.scrollLeft == old_position) {
            clear_interval();
        }
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      サムネイルを左スクロールします。
    //
    //      このメソッドはタイマー・イベントハンドラです。
    //
    function thumb_left() {
        var old_position = thumb.box.element.scrollLeft;

        thumb.box.element.scrollLeft = old_position - 1;
        
        if (thumb.box.element.scrollLeft == old_position) {
            clear_interval();
        }
    }


    ////////////////////////////////////////////////////////////////////////////////
    //
    //  概要：
    //      タイマーをクリアします。
    //
    function clear_interval() {
        if (timer_id) {
            clearInterval(timer_id);
            timer_id = 0;
        }
    }


    //  以下、内部データ構造（内部フィールド）

    var doc = document;

    var html = {
        element: doc.documentElement,
        style: null
    };

    html.style = get_style(html.element);

    var body = {
        element: doc.body,
        style: null
    };

    body.style = get_style(body.element);

    var light = {
        back: {
            element: null,
            style: null
        },
        box: {
            element: null,
            style: null,
            width: 740,
            height: 630,
            padding: {
                left: 2,
                top: 2,
                right: 2,
                bottom: 2
            }
        }
    };

    var main = {
        image: {
            element: null,
            style: null
            // 2008/06/20 [S] Kaigo
            , cache: null
            // 2008/06/20 [E] Kaigo
        }
    };

    var thumb = {
        box: {
            element: null,
            style: null,
            width: 0, // auto calculation
            height: 109
        }
    };

    var property = {
        box: {
            element: null,
            style: null
            // 2008/07/28 [S] Kaigo
            , foreground: "black"
            , background: "white"
            , padding: {
                left: 5,
                top: 2,
                right: 5,
                bottom: 2
            }
            // 2008/07/28 [E] Kaigo
        }
    };

    var buttons = {
        close: {
            element: null,
            style: null,
            alt: "閉じる",
            src: "ivm_close.gif",
            width: 24,
            height: 24,
            visible: false
        },
        index: {
            prev: {
                element: null,
                style: null,
                alt: "前へ",
                src: "ivm_prev.gif",
                width: 32,
                height: 32,
                visible: false
            },
            next: {
                element: null,
                style: null,
                alt: "次へ",
                src: "ivm_next.gif",
                width: 32,
                height: 32,
                visible: false
            }
        },
        thumb: {
            left: {
                element: null,
                style: null,
                alt: "左へ",
                src: "ivm_left.gif",
                width: 16,
                height: 109
            },
            right: {
                element: null,
                style: null,
                alt: "右へ",
                src: "ivm_right.gif",
                width: 16,
                height: 109
            }
        }
    };

    // 2008/06/20 [S] Kaigo
    var wait = {
        src: "ivm_wait.gif",
        cache: null
    };
    // 2008/06/02 [E] Kaigo

    var is_msie = (navigator.userAgent.indexOf("MSIE") >= 0);
    var is_firefox = (navigator.userAgent.indexOf("Firefox") >= 0);
    var is_safari = (navigator.userAgent.indexOf("Safari") >= 0);
    var is_unknown = !is_msie && !is_firefox && !is_safari;

    var scroll_base = is_safari ? body.element : html.element;

    var child_objects = [];
    var current_index = -1;
    var timer_id = 0;


    init();
}


////////////////////////////////////////////////////////////////////////////////
//
//  概要：
//      ImageViewManagerクラスのインスタンスを生成・初期化します。
//      ライト・ボックスを表示するための準備をします。
//
function ivm_hook(element) {
    element.onmouseover = null;

    var ivm = new ImageViewManager(element);
}

