var config = {
    createFormTarget: 'create-form-target',
    entryListTarget: 'entry-list-target',
    subDivTarget: 'sub-target',
    helpTarget:'help-target',
    prefTarget:"pref-target",
    loadingAnime:'<img src="/static/icon/tiny_red.gif" border="0" class="loadinganime">',
    finishtagregexp: new RegExp('^(終了|完了|finish|done)$'),
    publishtagregexp: new RegExp('^(public)$'),
    reqestOption: ['If-Modified-Since','Wed, 15 Nov 1995 00:00:00 GMT']
};
var FEMO = {
    selected_entry: 0,
    page: null,
    q: null,
    list_mode: null,
    sort_order: null,
    hide_finish_memo: null,
    entry: null,
    tag : {
        tags: [],
        select: function(){
            this.tags.clear();
            $A(arguments).each(function(new_tag){
                this.tags.push(new_tag);
            }.bind(this));
            this.tags = this.tags.compact();
        },
        add: function(new_tag) {
            this.tags = this.tags.without(new_tag);
            this.tags.push(new_tag);
            this.tags = this.tags.compact();
        },
        remove: function(remove_tag) {
            this.tags = this.tags.without(remove_tag);
            this.tags = this.tags.compact();
        },
        toQueryStr: function() {
            return this.tags.compact().map(function(param) {
               return 'tag=' + encodeURIComponent(param)
            }.bind(this)).join('&');
        },
        clear: function() {
            this.tags.clear();
        }
    },
    params: ['page','q','list_mode','sort_order','hide_finish_memo','entry'],
    toQueryStr: function(){
        var query =  this.params.select(function(param) {
                return this[param] != undefined || this[param] != null;
            }.bind(this)).map(function(param){
                    return param + '=' + encodeURIComponent(this[param])
            }.bind(this));
        query.push(this.tag.toQueryStr());
        return query.join('&');
    },
    clear: function(){
        //this.tag.clear();
        this.params.each(function(param){
                this[param]=null;
            }.bind(this));
    },
    list_mode_url: function(){
        var url;
        if(this.entry != null){
            return "/entries/one";
        }
        else if ( this.list_mode == 'search') {
            return "/entries/search";
        }
        return "/entries/list";
    }
};

String.prototype.toHashParamsEx = function() {
    var pairs = this.match(/^#?(.*)$/)[1].split('&');
    return pairs.inject({}, function(params, pairString) {
      var pair = pairString.split('=');
      if( params[pair[0]] != undefined ){
          if( typeof(params[pair[0]]).toLowerCase == "object"){
              params[pair[0]].push(pair[1]);
          }else{
              params[pair[0]] = [params[pair[0]],pair[1]];
          }
      } else {
          params[pair[0]] = pair[1];
      }
      return params;
    });
};

var selectEntry = {
    checkEntries: function(){
        var entries = $$('div.entry');
        if( entries.length == 0 ) return;
        entries.collect(function(e){ e.select('h2.entry-header > a')[0].removeClassName('selected_entry')});
        return entries;
    },
    checkPoint: function() {
        var entries = $$('div.entry');
        if( entries.length == 0 || FEMO.selected_entry == 0) return;
        if( FEMO.selected_entry < 1 && FEMO.selected_entry > entries.length ) return;
        var entry = entries[FEMO.selected_entry -1];
        return entry;
    },
    point: function(){
        var entry = this.checkPoint();
        if ( entry == undefined ) return;
        entry.select('h2.entry-header > a')[0].addClassName('selected_entry');
        Effect.ScrollTo(entry, { duration: 0.2 });
        var effect= new Effect.Highlight(entry.select('h2.entry-header > a')[0],{
            startcolor:"#ffff99",endcolor:"#ffffff",restorecolor:"#ffffff"});
    },
    nextf: 0,
    next: function(){
        var entries = this.checkEntries();
        if ( entries == undefined ) return;
        FEMO.selected_entry++;
        if( FEMO.selected_entry >= entries.length ) {
             FEMO.selected_entry = entries.length;
             if ( $('pagenate_next') && this.nextf > 0 ) {
                 this.previousf=0;
                 this.nextf=0;
                 FEMO.selected_entry=0;
                 $('pagenate_next').onclick();
                 return;
             }
             this.nextf++;
        }
        this.point();
    },
    previousf: 0,
    previous: function(){
        var entries = this.checkEntries();
        if ( entries == undefined ) return;
        FEMO.selected_entry--;
        if( FEMO.selected_entry > entries.length ) FEMO.selected_entry = entries.length;
        if( FEMO.selected_entry <= 1 ) {
            FEMO.selected_entry = 1;
            if ( $('pagenate_previous') && this.previousf > 0 ) {
                this.previousf=0;
                this.nextf=0;
                FEMO.selected_entry=300;
                $('pagenate_previous').onclick();
                return;
            }
            this.previousf++;
        }
        this.point();
    },
    edit: function(){
        var entry = this.checkPoint();
        if ( entry == undefined ) return;
        entry.select('h2.entry-header > a')[0].onmouseup();
    },
    changeDate: function(key) {
        if ( FEMO.tag.tags.grep(/^\d{4}-\d{2}-\d{2}$/).size() == 1 ) {
            var oldDate = FEMO.tag.tags.grep(/^\d{4}-\d{2}-\d{2}$/)[0];
            oldDate.match(/^(\d{4})-(\d{2})-(\d{2})$/);
            var newDate = new Date();
            newDate.setTime(
                new Date( parseFloat(RegExp.$1), parseFloat(RegExp.$2)-1, parseFloat(RegExp.$3) ).getTime() +
                    60*60*24*1000*key );
            FEMO.tag.remove( oldDate );
            new SelectTag(formatDate(newDate));
        }
    },
    nextDay: function(){
        this.changeDate(1);
    },
    previousDay: function(){
        this.changeDate(-1);
    }
}

var BlindDownUpdater = Class.create();
BlindDownUpdater.prototype = {
    initialize: function(container, url, options) {
        this.container = $(container);
        options.onComplete = this.onComplete.bind(this);
        options.requestHeaders = config.reqestOption;
        this.container.innerHTML = config.loadingAnime;
        this.options = options;
        Element.show(this.container);
        new Ajax.Request(url,options);
    },
    beforeBlindDown: function() {
        if(this.options.beforeBlindDown != undefined){
            this.options.beforeBlindDown();
        }
    },
    afterBlindDown: function() {
        if(this.options.afterBlindDown != undefined){
            this.options.afterBlindDown();
        }
    },
    onComplete: function(res) {
        Element.hide(this.container);
        this.container.innerHTML = res.responseText;
        this.beforeBlindDown();
        Effect.BlindDown(this.container,{
            duration: 0.3,
            afterFinish: this.afterBlindDown.bind(this)
        });
    }
};


//ヘルプ
var DoHelp = {
    load : function (){
        new BlindDownUpdater(config.helpTarget,"/help",{
            method:'get'
        });
        Element.addClassName('display_help_a','navigation_on');
    },
    close : function (){
        Effect.BlindUp(config.helpTarget,{duration:0.3});
        Element.removeClassName('display_help_a','navigation_on');
    },
    toggle : function (){
        if(Element.visible(config.helpTarget)){
            this.close();
        }else{
            this.load();
        }
    }
};

//LoadSubDiv
var LoadSubDiv = Class.create();
LoadSubDiv.prototype = {
    initialize: function(){
        this.markcurrenttag = arguments[0];
        this.entry = $(config.subDivTarget);
        this.params="";
        this.loading();
    },
    loading: function(){
        new BlindDownUpdater(this.entry,"/entries/tagcloud",{
            method:'get',
            parameters: this.params,
            beforeBlindDown: function(){
                if(this.markcurrenttag == 1) new MarkCurrentTag();
            }.bind(this)
        });
    }
};

//カレンダーのロード
var LoadCal = Class.create();
Object.extend(Object.extend(LoadCal.prototype, LoadSubDiv.prototype), {
    initialize: function(year,month){
        this.markcurrenttag = 1;
        this.entry = $(config.subDivTarget);
        this.params = "year="+year+"&month="+month;
        this.loading();
    }
});

//Tag Yellow Fade
var MarkCurrentTag = Class.create();
MarkCurrentTag.prototype = {
    initialize: function(){
        this.entry = $(config.subDivTarget);
        var classMatch = new RegExp('(latest|earliest|earlier|later|none|entrytag|relatetag)');
        var spans = document.getElementsByTagName('span');
        var finish_entry = [];
        for(var i=0;i<spans.length;i++){
            var ele = spans[i];
            var tagval = ele.firstChild.title;
            var ret = ele.className.match(classMatch);
            var match = RegExp.$1;
            if(ret == null) continue;
            if(match == 'entrytag'){
                Element.removeClassName(ele.parentNode.parentNode.parentNode,'finish_entry');
                if(tagval.match(config.finishtagregexp)){
                    finish_entry.push(ele.parentNode.parentNode.parentNode);
                }
            }
            if(match == 'entrytag' || match == 'relatetag'){
                if(tagval.match(config.finishtagregexp)){
                    Element.addClassName(ele,'finish_entry_tag');
                }else{
                    Element.removeClassName(ele,'finish_entry_tag');
                }
                if(tagval.match(config.publishtagregexp)){
                    Element.addClassName(ele,'public_entry_tag');
                }else{
                    Element.removeClassName(ele,'public_entry_tag');
                }
                if(tagval.search(/\d{4}-\d{2}-\d{2}/) > -1){
                    Element.addClassName(ele,'date_entry_tag');
                }else{
                    Element.removeClassName(ele,'date_entry_tag');
                }
            }

            if(FEMO.tag.tags.include(tagval)){
                var effect= new Effect.Highlight(ele,{
                        startcolor:"#ffff33",endcolor:"#ffff99",restorecolor:"#ffff99"});
            }else if(match != 'entrytag' && ele.style.backgroundColor.parseColor()=="#ffff99"){
                var effect= new Effect.Highlight(ele,{
                        startcolor:"#ffff99",endcolor:"#ffffff",restorecolor:"#ffffff"});
            }

        }
        for(var i=0;i<finish_entry.length;i++){
            Element.addClassName(finish_entry[i],'finish_entry');
        }
        if(FEMO.q) $('search_entry_f').q.value=FEMO.q;
        Element.removeClassName('display_today_memo_a','navigation_on');
        Element.removeClassName('display_latest_memo_a','navigation_on');
        if(FEMO.list_mode == null && FEMO.tag.tags.length == 0){
            Element.addClassName('display_latest_memo_a','navigation_on');
        }else if(FEMO.tag.tags.include(formatDate(new Date()))){
            Element.addClassName('display_today_memo_a','navigation_on');
        }
    }
};


// エントリーの新規作成
var CreateEntry = {
    load: function(){
        new BlindDownUpdater(config.createFormTarget,"/create/form",{
            method:'get',
            parameters: FEMO.tag.toQueryStr(),
            afterBlindDown: function(){
                Field.activate($("create_entry_f").elements['title']);
            }.bind(this)
        });
        Element.addClassName('create_new_memo_a','navigation_on');
    },
    close: function(){
        Form.disable('create_entry_f');
        Effect.BlindUp(config.createFormTarget,{duration:0.2});
        Element.removeClassName('create_new_memo_a','navigation_on');
    },
    toggle: function(){
        if(Element.visible(config.createFormTarget)){
            this.close();
        } else {
            this.load();
        }
    }
};

//新規作成コミット
var PostCreateEntry = Class.create();
PostCreateEntry.prototype = {
    initialize: function(form) {
        this.entry = $(config.createFormTarget);
        var params = Form.serialize(form);
        Form.disable(form);
        new Insertion.Top(this.entry,config.loadingAnime);
        new Ajax.Request("/create/post", {
            method: 'post',
            parameters: params,
            onComplete: this.completepost.bind(this),
            requestHeaders: config.reqestOption
        });
    },
    completepost: function(res){
        if( res.responseText.match(/^post_ok/) ){
            this.created_entry_id = res.responseText.split("|")[1];
            //新規エントリーの登録は成功
            Effect.BlindUp(this.entry,{duration:0.2, afterFinish: this.completeblindup.bind(this)});
            Element.removeClassName('create_new_memo_a','navigation_on');
        }else{
            this.entry.innerHTML=res.responseText;
        }
    },
    completeblindup: function(){
        new SelectOneAndSubDiv(this.created_entry_id);
    }
};


Hash.toQueryStringCompact =  function() {
    return this.select(function(pair) {
        return pair.value != undefined || pair.value != null;
    }).map(function(pair) {
      return pair.map(encodeURIComponent).join('=');
    }).join('&')
};

// エントリー一覧の読み込み
var LoadEntries = Class.create();
LoadEntries.prototype = {
    initialize: function(){
        this.initArgs.apply(this,arguments);
        this.loading();
    },
    initArgs: function(){
    },
    loading: function(){
        FEMO.selected_entry=0;
        DoHelp.close();
        var url = FEMO.list_mode_url();
        window.scroll(0,0);
        var querystr = FEMO.toQueryStr();
        //if(location.hash != ''){
        //    location.hash = '';
        //}
        //setTimeout(function(){location.hash = querystr},100);
        new BlindDownUpdater(config.entryListTarget,url,{
            method: 'get',
            parameters: querystr,
            beforeBlindDown: this.beforeBlindDown.bind(this),
            afterBlindDown: this.afterBlindDown.bind(this)
        });
    },
    beforeBlindDown: function(){
        new MarkCurrentTag();
    },
    afterBlindDown: function(){}
};

//hide_finish_memoを変更
var ChangeHideFinishMemo = Class.create();
Object.extend(Object.extend(ChangeHideFinishMemo.prototype, LoadEntries.prototype), {
    initArgs: function(flag){
        flag = (flag == 0) ? 1 : 0;
        FEMO.page = null;
        FEMO.hide_finish_memo = flag;
    }
});


//sortを変更
var ChangeSort = Class.create();
Object.extend(Object.extend(ChangeSort.prototype, LoadEntries.prototype), {
    initArgs: function(sort){
        FEMO.page = null;
        FEMO.sort_order = sort;
    }
});

//pageを変更
var ChangePage = Class.create();
Object.extend(Object.extend(ChangePage.prototype, LoadEntries.prototype), {
    initArgs: function(page){
        FEMO.page = page;
        this._selected_entry = FEMO.selected_entry;
    },
    afterBlindDown: function(){
         FEMO.selected_entry = this._selected_entry;
    }
});

//検索
var SearchEntries = Class.create();
Object.extend(Object.extend(SearchEntries.prototype, LoadEntries.prototype), {
    initArgs: function(q){
        FEMO.clear();
        FEMO.tag.clear();
        FEMO.list_mode = 'search';
        FEMO.q = q;
    }
});

//LateEntry
var LateEntries = Class.create();
Object.extend(Object.extend(LateEntries.prototype, LoadEntries.prototype), {
    initArgs: function(eid){
        this.eid = eid;
        FEMO.clear();
        FEMO.tag.clear();
        FEMO.sort_order = 1;
    },
    afterBlindDown: function(){
        var targetentry = $('entry-'+this.eid);
        window.scroll(0,Position.cumulativeOffset(targetentry)[1]);
    }
});

//Permalink記事表示
var SelectOne = Class.create();
Object.extend(Object.extend(SelectOne.prototype, LoadEntries.prototype), {
    initArgs: function(entry){
        FEMO.clear();
        FEMO.tag.clear();
        FEMO.entry = entry;
    }
});

//タグを選択
var SelectTag = Class.create();
Object.extend(Object.extend(SelectTag.prototype, LoadEntries.prototype), {
    initArgs: function(){
        FEMO.clear();
        FEMO.tag.select.apply(FEMO.tag,arguments);
    }
});

var SelectTagNotClear = Class.create();
Object.extend(Object.extend(SelectTagNotClear.prototype, LoadEntries.prototype), {
    initArgs: function(){
        FEMO.page = null;
        FEMO.tag.select.apply(FEMO.tag,arguments);
    }
});

//reload
var ReloadTag = Class.create(LoadEntries,{
    initArgs: function(){
        FEMO.page = null;
    }
});

//絞り込み
var RefineTag = Class.create();
Object.extend(Object.extend(RefineTag.prototype, LoadEntries.prototype), {
    initArgs: function(tag){
        FEMO.page = null;
        FEMO.tag.add(tag);
    }
});

//エントリー一覧とSubdiv読み込み
var SelectTagAndSubDiv = Class.create();
Object.extend(Object.extend(SelectTagAndSubDiv.prototype, SelectTag.prototype), {
    afterBlindDown: function(){
        new LoadSubDiv(1);
    }
});


var LoadEntriesAndSubDiv = Class.create();
Object.extend(Object.extend(LoadEntriesAndSubDiv.prototype, LoadEntries.prototype), {
    afterBlindDown: function(){
        new LoadSubDiv(1);
    }
});

//1つ表示してsubdiv表示
var SelectOneAndSubDiv = Class.create();
Object.extend(Object.extend(SelectOneAndSubDiv.prototype, SelectOne.prototype), {
    afterBlindDown: function(){
        new LoadSubDiv(1);
    }
});

//location.hashを読んで表示
var LoadHashAndSubDiv = Class.create();
Object.extend(Object.extend(LoadHashAndSubDiv.prototype, LoadEntries.prototype), {
    initArgs: function(){
        FEMO.clear();
        FEMO.tag.clear();
        var hash = location.hash.toHashParamsEx();
        FEMO.params.each(function(param){
            if(hash[param] != undefined) FEMO[param] = hash[param];
        });
        var tagtype = typeof(hash['tag']);
        if( tagtype.toLowerCase() == 'object' ){
            FEMO.tag.tags = hash['tag'];
        }else if( tagtype.toLowerCase() == 'string' ){
            FEMO.tag.add(hash['tag']);
        }
    },
    afterBlindDown: function(){
        new LoadSubDiv(1);
    }
});


//今日のエントリー読み込み
function formatDate (date) {
    var dt = date;
    var year = dt.getFullYear();
    var mon = dt.getMonth()+1;
    var dat = dt.getDate();
    var month = String("000" + mon).slice(-2);
    var date = String("000" + dat).slice(-2);
    var datestr = ""+year+"-"+month+"-"+date;
    return datestr;
};
var LoadToday = Class.create();
Object.extend(Object.extend(LoadToday.prototype, LoadEntries.prototype), {
    initArgs: function(){
        FEMO.clear();
        FEMO.tag.select(formatDate(new Date()));
    }
});


//エントリーの編集
var EditEntry = Class.create();
EditEntry.prototype = {
    initialize: function(eid){
        this.eid = eid;
        this.entry = $("entry-"+this.eid);
        Element.addClassName(this.entry,'edit_entry');
        new Ajax.Request("/edit/entry",{
            method:'get',
            parameters: $H({entry:this.eid}).toQueryString(),
            onComplete: this.onComplete.bind(this),
            requestHeaders: config.reqestOption
        });
    },
    onComplete: function(res){
        this.entry.innerHTML = res.responseText;
        new Effect.Shake(this.entry,{ distance: 3, duration: 0.3  });
        Field.activate($("entry_edit_f_"+this.eid).elements['title']);
    }
};


//エントリーの編集キャンセル
var CancelEditEntry = Class.create();
CancelEditEntry.prototype = {
    initialize: function(eid){
        this.eid = eid;
        this.entry = $("entry-"+this.eid);
        Form.disable("entry_edit_f_"+this.eid);
        new Ajax.Request("/entries/entry",{
            method:'get',
            parameters: $H({entry:this.eid}).toQueryString(),
            onComplete: this.onComplete.bind(this),
            requestHeaders: config.reqestOption
        });
    },
    onComplete: function(res){
        this.entry.innerHTML = res.responseText;
        Element.removeClassName(this.entry,'edit_entry');
        new MarkCurrentTag();
        new Effect.Shake(this.entry,{ distance: 3, duration: 0.3 });
    }
};

//エントリーの編集コミット
var PostEditEntry = Class.create();
PostEditEntry.prototype = {
    initialize: function(eid) {
        this.eid = eid;
        this.entry = $("entry-"+this.eid);
        this.form = $("entry_edit_f_"+this.eid);
        var params = Form.serialize(this.form);
        Form.disable(this.form);
        new Insertion.Top(this.entry,config.loadingAnime);
        new Ajax.Request("/edit/post", {
            method: 'post',
            parameters: params,
            onComplete: this.completepost.bind(this),
            requestHeaders: config.reqestOption
        });
    },
    completepost: function(res){
        if(res.responseText == "post_ok"){
            //エントリーの編集は成功
            new Ajax.Request("/entries/entry",{
                method:'get',
                parameters: $H({entry:this.eid}).toQueryString(),
                onComplete: this.onComplete.bind(this),
                requestHeaders: config.reqestOption
            });
        }else{
            this.entry.innerHTML = res.responseText;
        }
    },
    onComplete: function(res){
        this.entry.innerHTML = res.responseText;
        Element.removeClassName(this.entry,'edit_entry');
        new Effect.Shake(this.entry,{ distance: 3, duration: 0.3 });
        new LoadSubDiv(1);
    }
};

//エントリー削除
var DeleteEntry = Class.create();
DeleteEntry.prototype = {
    initialize: function(eid) {
        this.eid = eid;
        this.entry = $("entry-"+this.eid);
        new Ajax.Request("/edit/delete", {
            method: 'get',
            parameters: $H({entry:this.eid}).toQueryString(),
            onComplete: this.completepost.bind(this),
            requestHeaders: config.reqestOption
        });
    },
    completepost: function(res){
        Element.hide(this.entry);
        FEMO.page = null;
        if( FEMO.entry != undefined ) FEMO.entry = null;
        new LoadEntriesAndSubDiv();
    }
};



//設定
var LoadPref = {
    load: function(){
        DoHelp.close();
        this.entry = $(config.prefTarget);
        new BlindDownUpdater(this.entry,"/entries/pref",{
            method:'get'
        });
        Element.addClassName('display_pref_a','navigation_on');
    },
    close: function(){
        Form.disable('pref-form');
        Effect.BlindUp(config.prefTarget,{duration:0.3});
        Element.removeClassName('display_pref_a','navigation_on');
    },
    toggle: function(){
        if(Element.visible(config.prefTarget)){
            this.close();
        } else {
            this.load();
        }
    }
};

//設定POST
var PostPref = Class.create();
PostPref.prototype = {
    initialize: function(form) {
        this.entry = $(config.prefTarget);
        var params = Form.serialize(form);
        Form.disable(form);
        new Insertion.Top(this.entry,config.loadingAnime);
        new Ajax.Request("/entries/do_pref", {
            method: 'post',
            parameters: params,
            onComplete: this.completepost.bind(this),
            requestHeaders: config.reqestOption
        });
    },
    completepost: function(res){
        if(res.responseText == "post_ok"){
            //設定登録成功
            Effect.BlindUp(this.entry,{duration:0.2, afterFinish: this.completeblindup.bind(this)});
            Element.removeClassName('display_pref_a','navigation_on');
        }else{
            this.entry.innerHTML = res.responseText;
        }
    },
    completeblindup: function(){
        FEMO.page = null;
        FEMO.sort_order = null;
        //new LoadEntries();
        new LoadEntriesAndSubDiv();
    }
};


//function getPageScrolll and getPageSize from lightbox
//http://www.huddletogether.com/projects/lightbox/lightbox.js
function getPageScroll(){

    var yScroll;

    if (self.pageYOffset) {
        yScroll = self.pageYOffset;
    } else if (document.documentElement && document.documentElement.scrollTop){	 // Explorer 6 Strict
        yScroll = document.documentElement.scrollTop;
    } else if (document.body) {// all other Explorers
        yScroll = document.body.scrollTop;
    }

    arrayPageScroll = new Array('',yScroll) 
        return arrayPageScroll;
}

function getPageSize(){

    var xScroll, yScroll;

    if (window.innerHeight && window.scrollMaxY) {
        xScroll = document.body.scrollWidth;
        yScroll = window.innerHeight + window.scrollMaxY;
    } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
        xScroll = document.body.scrollWidth;
        yScroll = document.body.scrollHeight;
    } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
        xScroll = document.body.offsetWidth;
        yScroll = document.body.offsetHeight;
    }

    var windowWidth, windowHeight;
    if (self.innerHeight) { // all except Explorer
        windowWidth = self.innerWidth;
        windowHeight = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
        windowWidth = document.documentElement.clientWidth;
        windowHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
        windowWidth = document.body.clientWidth;
        windowHeight = document.body.clientHeight;
    }

    // for small pages with total height less then height of the viewport
    if(yScroll < windowHeight){
        pageHeight = windowHeight;
    } else { 
        pageHeight = yScroll;
    }

    // for small pages with total width less then width of the viewport
    if(xScroll < windowWidth){
        pageWidth = windowWidth;
    } else {
        pageWidth = xScroll;
    }

    arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight) 
        return arrayPageSize;
}



var OverLay = {
    show: function(){
        Element.show('overlay');
        Element.show('overlaid_box');
        this.center('overlaid_box');
    },
    hidefook: function(){},
    hide: function(){
        this.hidefook();
        Element.hide('overlay');
        Element.hide('overlaid_box');
    },
    center: function(element){
        element = $(element);
        var pagesize = getPageSize();
        var scrollsize = getPageScroll();

        $('overlay').style.height=pagesize[1]+"px";

        var elementDimensions = Element.getDimensions(element);
        var setX = ( pagesize[2]  - elementDimensions.width  ) / 2;
        var setY = ( pagesize[3] - elementDimensions.height ) / 2 + scrollsize[1];

        setX = ( setX < 0 ) ? 0 : setX;
        setY = ( setY < 0 ) ? 0 : setY;

        element.style.left = setX + "px";
        element.style.top  = setY + "px";
        element.style.display  = 'block';
    }
};

var TagWarp = {
    selectedTagsIndex: 0,
    visibleTagCount: 0,
    tags: [],
    show: function(){
        OverLay.show();
        OverLay.hidefook = this.hide.bind(this);
        $('tag_warp_input').value="";
        setTimeout(function(){
                $('tag_warp_input').value="";
                Field.focus('tag_warp_input');
            },1);
        new Ajax.Request("/entries/taglist", {
                method: 'get',
                    onComplete: this.onComplete.bind(this),
                    requestHeaders: config.reqestOption
                    });
        $('tag_warp_data').innerHTML=config.loadingAnime;
        $('tag_warp_input').onkeyup = TagWarp.keyup.bindAsEventListener(this);
        $('tag_warp_input').onkeydown = TagWarp.keydown.bindAsEventListener(this);
        $('tag_warp_input').onblur = function(){Field.focus('tag_warp_input')};
    },
    onComplete: function(res){
        $('tag_warp_data').innerHTML=res.responseText;
        var tags = document.getElementsByClassName('tag_warp_taglist',$('tag_warp_data'));
        this.tags = tags;
        this.visibleTagCount=tags.length;
        //this.selectedTagsIndex=0;
        this.markSelected();
    },
    hide: function(){
        OverLay.hidefook = function(){};
        $('tag_warp_input').onblur = function(){};
        $('tag_warp_input').onkeyup = function(){};
        $('tag_warp_input').onkeydown = function(){};
        $('tag_warp_input').blur();
        OverLay.hide();
    },
    quotemeta: function (string) {
        return string.replace(/(\W)/, "\\$1");
    },
    keydown: function(event){
        if( event.keyCode == Event.KEY_UP ){
            this.markPrevious();
            this.markSelected();
            if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
            return;
        } else if( event.keyCode == Event.KEY_DOWN ){
            this.markNext();
            this.markSelected();
            if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
            return;
        } else if ( event.keyCode == Event.KEY_RETURN ){
            this.selectTag();
            Event.stop(event);
            return;
        } else if ( event.keyCode == Event.KEY_TAB ){
            Event.stop(event);
            return;
        }
    },
    keyup: function(event){
        setTimeout(function(){this.grepList();}.bind(this),10);
    },
    markPrevious: function() {
        if(this.selectedTagsIndex > 0) this.selectedTagsIndex--
            else this.selectedTagsIndex = this.visibleTagCount-1;
    },
    markNext: function() {
        if(this.selectedTagsIndex < this.visibleTagCount-1) this.selectedTagsIndex++
            else this.selectedTagsIndex = 0;
    },
    markSelected: function(){
        if(this.tags.length == 0) return;
        var j=0;
        var selectedtag;
        for( var i=0; i < this.tags.length; i++ ){
            if(Element.visible(this.tags[i])){
                if(this.selectedTagsIndex == j){
                    selectedtag=this.tags[i];
                    Element.addClassName(this.tags[i],"selected");
                }else{
                    Element.removeClassName(this.tags[i],"selected");
                }
                j++;
            }
        }
        if(selectedtag == undefined) return;
        var offset = Position.cumulativeOffset(selectedtag)[1] - Position.cumulativeOffset(this.tags[0])[1];
        if(offset > Element.getHeight('tag_warp_data')) $('tag_warp_data').scrollTop = offset;
        if(offset < Element.getHeight('tag_warp_data')) $('tag_warp_data').scrollTop = 0;
    },
    selectTag: function(){
        var tags = this.tags;
        var visibletags = new Array();
        for( var i=0; i < tags.length; i++ ){
            if(Element.visible(tags[i])) visibletags.push(tags[i]);
        }
        new SelectTag(visibletags[this.selectedTagsIndex].innerHTML);
        setTimeout(function(){this.hide();}.bind(this),100);
    },
    grepList: function(){
        var regex = new RegExp(this.quotemeta($F('tag_warp_input')), "i");
        var tags = this.tags;
        var f = 0;
        for (var i = 0; i < tags.length; i++) {
            if (tags[i].innerHTML.match(regex)) {
                Element.show(tags[i]);
                f++;
            } else {
                Element.hide(tags[i]);
            }
        }
        if(this.visibleTagCount != f){
            this.visibleTagCount = f;
            this.selectedTagsIndex = 0;
            this.markSelected();
        }
    }
};



