﻿// 時刻表示機能
var WorldClock = function (optional) {
    /**
     * 設定オブジェクト
     * @type Object
     * @default {}
     */
    this.options = {
        timeDiff: 0, // 時差
        node: ""
    }
    /**
     * タイマーID
     * @type Number
     * @default null
     */
    this.ID = null; // ID
    /**
     * 時差を反映した、現在の時間オブジェクト
     * @type Object
     * @default {}
     */
    this.currentData = {
        year: "",
        month: "",
        date: "",
        hours: "",
        minutes: ""
    };
    this.$node;

    // 設定オブジェクト反映
    this.setOptions(optional);
};

WorldClock.prototype = (function () {
    // private static variables
    var __self,
        _updateFuncs = {},
        _count = 0,
        _duration = 1000,
        _clockID,
        _nowDate = new Date(),
        _currentTime = null,
        _previousTime = null;

    // public method
    __self = {
        /**
         * 初期化
         */
        init: function () {
            var opts = this.options;

            this.$node = $(opts["node"]);
            if (!this.$node.length) {
                return;
            }
            this.ID = "clock-" + _count++;
            this.start();
        },
        /**
         * 動作開始
         */
        start: function () {
            var self = this;
            this.update();

            // アップデート関数を登録
            _updateFuncs[self.ID] = (function () {
                return function(){
                    self.update();
                }
            }());

            // インターバル処理は初回のみ実行される
            if (_clockID == undefined) {
                _clockID = setInterval(function () {
                    // 時間（分）が更新されていたらアップデート処理を走らせる
                    if (self.timeHasChanged()) {
                        for (var i in _updateFuncs) {
                            if (_updateFuncs[i]) {
                                _updateFuncs[i]();
                            }
                        }
                    }
                }, _duration);
            }
        },
        /**
         * ローカルマシンの時間を取得し、「分」が更新されているか調べる
         * @return {Boolean} 更新されていたらtrue、そうでないならfalse
         */
        timeHasChanged: function () {
            var ret          = false;

            _nowDate      = new Date();
            _currentTime = {
                year    : _nowDate.getUTCFullYear(),
                month   : _nowDate.getUTCMonth(),
                day     : _nowDate.getUTCDate(),
                hours   : _nowDate.getUTCHours(),
                minutes : _nowDate.getUTCMinutes()
            };

            // 分で比較
            if (_previousTime && _currentTime["minutes"] != _previousTime["minutes"]) {
                ret = true;
            }
            // 更新
            _previousTime = _currentTime;
            return ret;
        },
        /**
         * 設定されている時差を反映して、$nodeを更新する
         */
        update: function () {
            var year         = _nowDate.getUTCFullYear(),
                month        = _nowDate.getUTCMonth(),
                day          = _nowDate.getUTCDate(),
                hours        = _nowDate.getUTCHours(),
                minutes      = _nowDate.getUTCMinutes(),
                timeDiffDate = new Date(year, month, day, hours + this.options.timeDiff, minutes);

            // 現在の時間を取得
            this.currentData = {
                year: timeDiffDate.getFullYear(),
                month: timeDiffDate.getMonth() + 1,
                day: timeDiffDate.getDate(),
                hours: timeDiffDate.getHours(),
                minutes: timeDiffDate.getMinutes()
            };
            var td = this.currentData;
            var y = td["year"] 
            var m = td["month"] 
            var d = td["day"]
            var h = td["hours"] 
            var mi = td["minutes"] 
            var yString = zeroPadding(y, 4);
            var mString = zeroPadding(m, 2);
            var dString = zeroPadding(d, 2);
            var hString = zeroPadding(h, 2);
            var miString = zeroPadding(mi, 2);
            // 値を反映する
            this.$node.html(hString + ":" + miString + " " + yString + "/" + mString + "/" + dString);
        },
        /**
         * オプションを適用する
         */
        setOptions : function(optional) {
            this.options = $.extend(this.options, optional);
        }
    };

    /**
     * ゼロ埋関数
     */
    function zeroPadding(str,digitNum){
        var zero = "";
        str = str.toString();
        for (var i = 0; i < digitNum; i++) zero += "0";
        return (zero + str).slice(- digitNum );
    }

    return __self
 })();

// 天気表示機能
var WetherSlide = function (optional) {
    /**
     * 設定オブジェクト
     * @type Object
     * @default {}
     */
    this.options = {
        autoTime : 3000, // 自動切り替え時間
        node : "", // 対象ノード
        next : "", // 対象コントローラ（前）
        prev : "", // 対象コントローラ（次）
        jsonPath : "/st/json/forecast.json", // JSONのパス
        activeClass : "active", // アクティブ状態のnodeに付与されるクラス
        errorHTML : "<li class='connect-error'>通信に失敗しました</li>" // JSONの取得に失敗した際にnodeに挿入される文字列
    };
    this.$node;
    this.$next;
    this.$prev;
    this.autoTime;
    this.jsonPath;

    this.itemSet = [];
    this.itemSetLength = 0;
    this.curCount = 0;
    this.timerID = null;
    this.HTMLTemplate = ''
        + '<li class="weather-item"><p class="weather-area"><img src="%AREA_PATH%" alt="%AREA_TEXT%" /></p></li>'
        + '<li class="weather-item"><p class="weather-icon"><img src="%WEATHER_PATH%" alt="" width="%WEATHER_WIDTH%" height="%WEATHER_HEIGHT%" /></p></li>'
        + '<li class="weather-item"><p class="weather-red">%TEMPERATURE_MAX%℃</p><p class="weather-blue">%TEMPERATURE_MIN%℃</p></li>';

    // 設定オブジェクト反映
    this.setOptions(optional);
};

WetherSlide.prototype = (function () {
    var __self;

    __self = {
        /**
         * 初期化
         */
        init : function () {
            var opts = this.options;

            this.$node = $(opts["node"]);
            if (!this.$node.length) {
                return;
            }
            this.$prev = this.$node.find(opts["prev"]);
            this.$next = this.$node.find(opts["next"]);
            this.autoTime = opts.autoTime;
            this.jsonPath = opts.jsonPath;

            this.loadJSON();
            return;
        },
        /**
         * JSONをロードする
         */
        loadJSON : function () {
            var self = this;
            var url = this.jsonPath;
            $.ajax({
                url : url,
                success : function (jsonText) {
                    self.onJSONConnectSuccess(jsonText);
                },
                error : function () {
                    self.onJSONConnectError();
                }
            });
        },
        /**
         * コントローラを有効にする
         */
        startInteraction : function () {
            var self = this;

            (function(objs) {
                $.each(objs, function(i, obj) {
                    obj["$node"].bind("click", function () {
                        self.changeItem(obj["count"]);
                        return false;
                    }).find("img").css({
                        cursor : "pointer"
                    });
                });
            })([{
                $node : this.$prev,
                count : -1
            },{
                $node : this.$next,
                count : 1
            }]);
        },
        /**
         * タイマーを開始する
         */
        startTimer : function () {
            var self = this;
            this.stopTimer();
            this.timerID = setTimeout(function() {
                self.changeItem(1);
            }, this.autoTime);
        },
        /**
         * タイマーを停止する
         */
        stopTimer : function () {
            clearTimeout(this.timerID);
        },
        /**
         * JSONの取得に成功した際のハンドラ
         */
        onJSONConnectSuccess : function (jsonText) {
            var json = JSON.parse(jsonText);
            this.setDOM(json);
            this.$node.addClass(this.options.activeClass);
            this.changeItem(0);
            this.startTimer();
            this.startInteraction();
        },
        /**
         * JSONの取得に失敗した際のハンドラ
         */
        onJSONConnectError : function () {
            this.$node.html(this.options.errorHTML);
            this.$node.addClass(this.options.activeClass);
        },
        /**
         * カウントプロパティを更新する
         */
        updateCount : function (dist) {
            this.preCount = this.curCount;
            this.curCount += dist;
            if (this.curCount < 0) {
                this.curCount = this.itemSetLength - 1;
            }else if (this.curCount > this.itemSetLength - 1) {
                this.curCount = 0;
            }
        },
        /**
         * アイテムを切り替える
         */
        changeItem : function (dist) {
            this.updateCount(dist);

            var $pre = this.itemSet[this.preCount];
            var $cur = this.itemSet[this.curCount];
            $pre.hide();
            $cur.show();

            this.startTimer();
        },
        /**
         * JSONを使用してDOMを初期化する
         * @param {Object} jsonオブジェクト
         */
        setDOM : function (json) {
            var results = json["results"];
            var self = this;
            var html = "";
            $.each(results, function (i, elem) {
                var temp = self.HTMLTemplate || "";
                var loc = elem["location"] || {};
                var image = elem["image"] || {};
                var temperature = elem["temperature"] || {};

                // JSONデータ取得
                var areaPath = loc["image_url"];
                var areaText = loc["area"];
                var weatherPath = image["url"];
                var weatherWidth = image["width"];
                var weatherHeight = image["height"];
                var temperatureMax = temperature["max"];
                var temperatureMin = temperature["min"];
                if (temperatureMax == "undefined"
                || temperatureMax == "null"
                || temperatureMax != 0 && !temperatureMax) {
                    temperatureMax = "-";
                }
                if (temperatureMin == "undefined"
                || temperatureMax == "null"
                || temperatureMin != 0 && !temperatureMin) {
                    temperatureMin = "-";
                }
                // 置換
                temp = temp.replace("%AREA_PATH%", areaPath);
                temp = temp.replace("%AREA_TEXT%", areaText);
                temp = temp.replace("%WEATHER_PATH%", weatherPath);
                temp = temp.replace("%WEATHER_WIDTH%", weatherWidth);
                temp = temp.replace("%WEATHER_HEIGHT%", weatherHeight);
                temp = temp.replace("%TEMPERATURE_MAX%", temperatureMax);
                temp = temp.replace("%TEMPERATURE_MIN%", temperatureMin);
                html += temp;
            });
            // 反映
            this.$next.after(html);

            // li要素3つ毎に1セットとしてitemSetに保管
            var $item = this.$node.find(".weather-item");
            var itemLen = $item.length;
            var loopLen = Math.ceil(itemLen / 3);
            var i = 0;
            for (i; i < loopLen; i++) {
                this.itemSet.push($item.slice(i * 3, (i + 1) * 3));
                this.itemSet[i].hide();
            }
            this.itemSetLength = this.itemSet.length;
            this.curCount = Math.floor(this.itemSetLength * Math.random());
        },
        /**
         * オプションを適用する
         */
        setOptions : function(optional) {
            this.options = $.extend(this.options, optional);
        }
    };

    return __self;
})();

// 初期化する
$(function(){
    var wc = new WorldClock({
        timeDiff : 9,
        node : ".jtime"
    });
    wc.init();

    var ws = new WetherSlide({
        node : "#weather-and-time ul",
        prev : ".weather-c2",
        next : ".weather-c1"
    });
    ws.init();
});

