var Rating = {};
Rating.Strage = new Class.create();
Rating.Strage.prototype = {
    _list : null,
    initialize : function(){
        if (!this._list) {
            this._list = {};
        }
    },
    add : function (key, value) {
        if (this.has(key)) {
            this.remove(key);
        }
        if (typeof(value.cloneNode)=='undefined') {
            this._list[key] = value;
        } else {
            this._list[key] = value.cloneNode(true);
        }
    },
    remove : function (key) {
        delete this._list[key];
    },
    get : function (key) {
        return this._list[key];
    },
    has : function (key) {
        return (typeof(this._list[key])=='undefined') ? false : true;
    },
    count : function () {
        var counter=0;
        $H(this._list).each(function(){
            counter++;
        }.bind(counter));
        return counter;
    }
};
Ozein.Rating = new Class.create();
Ozein.Rating.prototype = {
    _cacheRatingEvf : null,
    initialize: function(node, options) {
        this.setOptions(options);
        this.node = node;
        var w = (this.options.width || node.getWidth());
        this._cacheRatingEvf = new Rating.Strage();
        this.stepWidth = w/this.options.step;
        this.preloadImage();
        this.preStep = node.getAttribute('ozein_rating_step');
        this.ratingId = node.getAttribute('ozein_rating_id');
        this.changeImage(node.getAttribute('ozein_rating_step'));
        this.posX = null;
        
        this._setEvent();
    },
    setOptions: function(options) {
        this.options = {
            bid : null,
            imagePath: '/img/',
            imageName: 'rating_star_<$>.gif',
            step: 5,
            clear: null,
            useMessage: false,
            message: {
                0 : '未評価',
                1 : '少し気になる',
                2 : '興味がある',
                3 : '結構気になる',
                4 : '大変気になる',
                5 : '気になって仕方ない'
            }
        }
        Object.extend(this.options, options || {});
    },
    _setEvent: function() {
        var evfKey = "";
        var bukkenId = this.options.bid;
        // mousemove
        evfKey = 'rating_mousemove-'+bukkenId;
        if (this._cacheRatingEvf.has(evfKey)) {
            Event.stopObserving(this.node, 'mousemove', this._cacheRatingEvf.get(evfKey));
            this._cacheRatingEvf.remove(evfKey);
        }
        this._cacheRatingEvf.add(evfKey, this.rating.bindAsEventListener(this));
        Event.observe(this.node, 'mousemove', this._cacheRatingEvf.get(evfKey));
        
        // click
        evfKey = 'rating_fix-'+bukkenId;
        if (this._cacheRatingEvf.has(evfKey)) {
            Event.stopObserving(this.node, 'click', this._cacheRatingEvf.get(evfKey));
            this._cacheRatingEvf.remove(evfKey);
        }
        this._cacheRatingEvf.add(evfKey, this.fix.bindAsEventListener(this));
        Event.observe(this.node, 'click', this._cacheRatingEvf.get(evfKey));

        // mouseout
        evfKey = 'rating_back-'+bukkenId;
        if (this._cacheRatingEvf.has(evfKey)) {
            Event.stopObserving(this.node, 'mouseout', this._cacheRatingEvf.get(evfKey));
            this._cacheRatingEvf.remove(evfKey);
        }
        this._cacheRatingEvf.add(evfKey, this.back.bindAsEventListener(this));
        Event.observe(this.node, 'mouseout', this._cacheRatingEvf.get(evfKey));

        // clear click
        var resets = document.getElementsByAttribute('ozein_rating_reset_id', this.options.clear);
        evfKey = 'rating_clear-'+bukkenId;
        if (this._cacheRatingEvf.has(evfKey)) {
            Event.stopObserving(resets[0], 'click', this._cacheRatingEvf.get(evfKey));
            this._cacheRatingEvf.remove(evfKey);
        }
        this._cacheRatingEvf.add(evfKey, this.clear.bindAsEventListener(this));
        Event.observe(resets[0], 'click', this._cacheRatingEvf.get(evfKey));
    },
    preloadImage: function() {
        this.ratingImg = [];
        var op = this.options;
        for (var r=0; r<=op.step; ++r) {
            var img = document.createElement('img');
            img.src = op.imagePath + op.imageName.replace('<$>', r);
            this.ratingImg.push(img);
        }
    },
    rating: function(e) {
        //評価を変動させる
        var step = this.getStep(e);
        if(this.preStep != step) {
            this.preStep = step;
            this.changeImage(this.preStep);
        }
    },
    fix: function(e) {
        //評価を決定する
        var step = this.getStep(e);
        if(this.node.getAttribute('ozein_rating_step') != step) {
            this.beacon(step);
            this.changeStep(step);
            this.changeImage(step);
        }
    },
    back: function(e) {
        //評価を元に戻す
        var step = this.node.getAttribute('ozein_rating_step')
        this.changeImage(step);
        this.preStep = step;
    },
    clear: function(e) {
        //評価の初期化
        this.beacon(0);
        this.changeStep(0);
        this.changeImage(0);
    },
    getStep: function(e) {
        //評価の段階を取得する
        var targetNode = this.node;
        var pointPosition = Position.cumulativeOffset(targetNode);

        this.posX = pointPosition.shift();
        var distance = Event.pointerX(e) - this.posX;
        var step = Math.ceil(distance/this.stepWidth);
        return step;
    },
    changeStep: function(step) {
        //評価アトリビュートを変更
        var ratings = document.getElementsByAttribute('ozein_rating_id', this.ratingId);
        for(var i=0;i<ratings.length;i++) {
            ratings[i].setAttribute('ozein_rating_step',step);
        }
    },
    changeImage: function(step) {
        //画像の変更
        if (step < 0 || step > this.options.step) return;
        var ratings = document.getElementsByAttribute('ozein_rating_id', this.ratingId);
        for(var i=0;i<ratings.length;i++) {
            if(ratings[i].tagName.eqi('img')) {
                ratings[i].src = this.ratingImg[step].src;
            }
        }
        //メッセージ変更
        this.changeMessage(step);
    },
    changeMessage: function(step) {
        //メッセージ変更
        if(!this.options.message || this.options.useMessage == 'false') return null;
        if(this.options.message[step]) {
            var ratings = document.getElementsByAttribute('ozein_rating_message_id', this.ratingId);
            for(var i=0;i<ratings.length;i++) {
                ratings[i].innerHTML = this.options.message[step];
            }
        }
    },
    beacon: function(rating) {
        //ビーコン埋め込み
        if(!this.options.bid) return null;
        var beacon = new Ozein.Beacon(null,{url:'/Mylist/post-rating/'});
        beacon.addQuery('b='+this.options.bid);
        beacon.addQuery('star='+rating);
        beacon.send();
    }
}
