/**
 * ベースライブラリ
 *
 * @copyright 2008 dotAster Inc.
 * @version   0.1.0
 * @require   jquery.js
 */
$(function() {
  $.fn.base = function() {};

  /**
   * 長いページで「このページの一番上に戻る」を表示する
   *
   * @param string  selector 比較用オブジェクト特定用セレクタ
   * @param integer limit    比較用オブジェクトの高さ
   *
   * @notice HTML内に「このページの一番上に戻る」リンクの記述が必要。
   *
   * @return void
   */
  $.fn.base.showPagetop = function(selector, limit) {
    if ($(selector).height() > limit) {
      $('#pagetopEnd').css({'display' : 'block'});
    }
  };

  /**
   * class="rollOver"を持つ画像のロールオーバー
   *
   * @param object config
   * + string selector ロールオーバー画像を特定させるセレクタ
   * + string postfix  ロールオーバー画像のファイル名に付ける接尾辞
   *
   * @return void
   */
  $.fn.base.addRollOver = function(config) {
    var config = $.extend({
                             selector : '.rollOver',
                             postfix : '_o'
                          },
                          config);

    $(config.selector).each(function() {
      this.imgSrc = ['up', 'o'];
      this.imgSrc['up'] = $(this).attr('src');
      this.imgSrc['o'] = this.imgSrc['up'].replace(/(\.gif|\.jpg|\.png)/, config.postfix+"$1");
      $(this).hover(function(){ $(this).attr('src', this.imgSrc['o']); }, function(){ $(this).attr('src', this.imgSrc['up']); });
    });
  };

  /**
   * スムーススクロール
   *
   * @param object config
   * + integer deceleration 減速開始距離
   * + integer ratio        減速率
   * + integer speed        移動速度
   *
   * @return void
   */
  $.fn.base.smoothScroll = function(config) {
    var config = $.extend({
                             deceleration : 200,
                             ratio : 2,
                             speed : 200
                          },
                          config);
    $('a[href^=#], area[href^=#]').not('a[href=#], area[href=#]').each(function() {
      var d, timer;
    
      $(this).click(function() {
        var to = document.getElementById(this.href.split('#')[1]);
        if(this.href.replace(/\#[a-zA-Z0-9]*/,"") == location.href.replace(/\#[a-zA-Z0-9]*/,"")){
          d = getPosition(to).y - getPosition(this).y;
          timer = setInterval( function() { setPosition(config.deceleration, config.ratio, config.speed, timer) },100);
          return false;
        }
      });

      var getPosition = function(elem) {
        var obj = new Object();
        obj.x = elem.offsetLeft;
        obj.y = elem.offsetTop;

        while(elem.offsetParent) {
          elem = elem.offsetParent;
          obj.x += elem.offsetLeft;
          obj.y += elem.offsetTop;
        }
        return obj;
      }

      var setPosition = function(length, ratio, speed, timer) {
        var moveD;
        if(Math.abs(d) > length){
          moveD = (d > 0) ? speed : -speed;
        } else {
          moveD = Math.round(d / ratio);
        }

        parent.scrollBy(0, moveD);
        d = d - moveD;

        if(moveD == 0){
          clearInterval(timer);
          d = 0;
        }
      }
    });
  };

  /**
   * フォーム入力支援
   *
   * @param object config
   * + string groupClass      適用範囲
   * + string checkAllClass   トリガーを設定する要素に付けるクラス名（全てのチェックボックスにチェック）
   * + string uncheckAllClass トリガーを設定する要素に付けるクラス名（全てのチェックボックスのチェック解除）
   * + string uncheckClass    トリガーを設定する要素に付けるクラス名（ラジオボタンのチェック解除）
   *
   * @notice ネストには非対応（一番外側のgroupClassの中身に対して適用）
   *
   * @return void
   */
  $.fn.base.formHelper = function(config) {
    var config = $.extend({
                             groupClass : 'checkGroup',
                             checkAllClass : 'checkAll',
                             uncheckAllClass : 'uncheckAll',
                             uncheckClass : 'uncheck'
                          },
                          config);
    var checkbox = {
      checkAll : function() {
        $('.' + config.checkAllClass).each(function() {
          $(this).click(function() {
            change(this, 'checkbox', true);
          });
        });
      },
      uncheckAll : function() {
        $('.' + config.uncheckAllClass).each(function() {
          $(this).click(function() {
            change(this, 'checkbox', false);
          });
        });
      }
    };
    var radio = {
      uncheck : function() {
        $('.' + config.uncheckClass).each(function() {
          $(this).click(function() {
            change(this, 'radio', false);
          });
        });
      }
    };
    var change = function(elem, type, checked) {
      $(elem).parents().filter('.' +config.groupClass).find('input[@type="' + type + '"]')
             .attr('checked', checked);
    };

    checkbox.checkAll();
    checkbox.uncheckAll();
    radio.uncheck();
  }

  /**
   * class="jumpMenu"を持つプルダウンをジャンプメニューに
   *
   * + string className
   * + string frame     フレーム名
   *
   * @return void
   */
  $.fn.base.jumpMenu = function(config) {
    var config = $.extend({
                             className : 'jumpMenu',
                             frame     : ''
                          },
                          config);
    $('.' + config.className).each(function() {
      $(this).change(function() {
        url = this.options[this.selectedIndex].value;
        if (config.frame) {
          parent.frames[config.frame].location.href = url;
        } else {
          location.href = url;
        }
      });
    });
  }

  /**
   * 外部リンク、ドキュメント（.doc, .xls, .pdf）へのリンクを別ウィンドウで開く
   *
   * @param object config
   * + boolean newWindow false=別ウィンドウで開かずに、下記クラス名のみ追加する
   * + string  className
   *
   * @return void
   */
  $.fn.base.newWindow = function(config) {
    var config = $.extend({
                             newWindow : true,
                             className : 'newWindow'
                          },
                          config);
    var a  = $('*').filter('a[href^="http://"], a[href^="https://"]')
                   .not('a[@href^="http://' + document.domain + '/"]')
                   .not('a[@href^="https://' + document.domain + '/"]')
                   .add('a[@href$=".pdf"], a[@href$=".doc"], a[@href$=".xls"]');
    if (config.newWindow) {
      a.click(function() {
        window.open(this.href, '_blank');
        return false;
      });
    }
    a.addClass(config.className);
  }

  /**
   * 画像への直リンクをthickboxで表示
   *
   * @require thickbox.js
   * @require thickbox.css
   *
   * @return void
   */
  $.fn.base.thickbox = function() {
    try {
      tb_init('a[@href$=".jpg"]:not(.thickbox), a[@href$=".gif"]:not(.thickbox), a[@href$=".png"]:not(.thickbox)');
    } catch(e) {
    }	
  }

  /**
   * 擬似クラス（:first-child, :last-child, :empty, :nth-class-odd, :nth-class-even）
   * の役割を持つクラス名を追加
   *
   * @param object config
   * + string oddClass
   * + string evenClass
   *
   * @return void
   */
  $.fn.base.addPseudoClass = function(config) {
    var config = $.extend({
                            oddClass  : 'odd',
                            evenClass : 'even'
                          },
                          config);

    $('ul, ol').each(function() {
      $(this).children('li:odd').addClass(config.evenClass);
      $(this).children('li:even').addClass(config.oddClass);
    });
    $('table, tbody').each(function() {
      $(this).children('tr:odd').addClass(config.evenClass);
      $(this).children('tr:even').addClass(config.oddClass);
    });

    $('body :first-child').addClass('firstChild');
    $('body :last-child').addClass('lastChild');
    $('body :empty').addClass('empty');
  };

  /**
   * クラス名「.js」を持つ要素を表示
   *
   * @notice JavaScript offの時に非表示にするなどして使用
   *
   * @return void
   */
  $.fn.base.showJs = function() {
    $('.js').each(function() {
      $(this).css({'display' : 'block'});
    });
  };

  /**
   * 自分自身へのリンクにクラス名を追加
   *
   * @param object config
   * + string currentClass
   * + string parentClass
   * + string changeImg    true=画像を差し替え
   * + string postfix      画像を差し替えするときにファイル名に付ける接尾辞
   *
   * @return void
   */
  $.fn.base.addCurrent = function(config) {
    var config = $.extend({
                            currentClass : 'current',
                            parentClass : 'parent',
                            changeImg : false,
                            postfix : '_cr'
                          }, config);
    $('a[href]').each(function() {
      var isImg = false;
      if(this.href.replace(/\#[a-zA-Z0-9]+/,"") == location.href.replace(/\#[a-zA-Z0-9]+/,"") &&
         !this.href.split('#')[1]) {
        $(this).addClass(config.currentClass);

        //画像の差し替え
        if (config.changeImg){
          $(this).find('img').each(function() {
            this.imgSrc = [];
            this.imgSrc['up'] = $(this).attr('src');
            this.imgSrc['cr'] = this.imgSrc['up'].replace(/(\.gif|\.jpg|\.png)/, config.postfix+"$1");
            $(this).attr('src', this.imgSrc['cr']);
          });
        }
      }
    });
  };

  /**
   * ナビゲーションメニューにカレント設定
   *
   * @string nav string
   *
   * @notice <ul><li>を使用したナビゲーションのみ有効
   * @notice HTML内でbody#id名 = #nav li.class名とする
   *
   * @return void
   */
  $.fn.base.addCurrentToNav = function(nav) {
    var bodyId = $('body')[0].id;
    $('#' + nav + ' li.' + bodyId + ' a').addClass('current');
  };

  /**
   * フォントサイズ変更
   *
   * @param object config
   * + string  id          フォントサイズ変更ボタンを表示させる要素を特定するためのセレクタ
   * + integer defaultSize クッキーを読み出せなかったときにカレント状態にするボタン
   * + array   liClass
   * + array   bodyClass
   * + array   text        <li>タグ内テキスト
   * + array   sizeIE6     フォントサイズ（IE6）
   * + array   sizeIE7     フォントサイズ（IE7）
   * + array   sizeOther   フォントサイズ（上記以外）
   * + integer expires     クッキーの有効期限（単位:日）
   *
   * @notice configにあるプロパティの配列の要素数によって切り替え段階を変更可
   *
   * @return void
   */
  $.fn.base.fontSizeChanger = function(config) {
    var config = $.extend({
                            id : '#fontSize',
                            defaultSize : 0,
                            liClass : ['s', 'm', 'l'],
                            bodyClass : ['fontSizeS', 'fontSizeM', 'fontSizeL'],
                            text : ['S', 'M', 'L'],
                            sizeIE6 : ['xx-small', 'x-small', 'medium'],
                            sizeIE7 : ['x-small', 'small', 'large'],
                            sizeOther : ['10px', '13px', '16px'],
                            expires : 90
                          }, config);
    var len = config.bodyClass.length;
    var cookieName = {
      current : '10CfontSizeChanger'
    };
    var i;

    var initialize = function() {
      // HTML中の<div>内に<ul><li>が存在しないとき
      if (!$(config.id + ' ul li').length) {
        var html = '<ul>';
        for (i = 0; i < len; i++) {
          html += '<li class="' + config.liClass[i] + '"><a href="#">' + config.text[i] + '</a></li>';
        }
        html += '</ul>';
        $(config.id).prepend(html);
      }

      var on = $.cookie(cookieName.current) || config.defaultSize;
      $(getSelector(on)).addClass('current')
      $('body').addClass(config.bodyClass[on]);

      for (i = 0; i < len; i++) {
        $(getSelector(i)).bind('click', {on : i}, change);
      }
    }

    var change = function(event) {
      for(i = 0; i < len; i++) {
        $(getSelector(i)).removeClass('current');
        $('body').removeClass(config.bodyClass[i]);
      }
      $(getSelector(event.data.on)).addClass('current')
      $('body').css({'font-size' : config[getSizeType()][event.data.on]})
               .addClass(config.bodyClass[event.data.on]);

      $.cookie(cookieName.current, event.data.on, { expires : config.expires });
    };

    var getSelector = function(n) {
      return config.id + ' li.' + config.liClass[n] + ' ' + 'a';
    }

    var getSizeType = function() {
      if(navigator.userAgent.indexOf("MSIE 6") >= 0) {
        return 'sizeIE6';
      } else if(navigator.userAgent.indexOf("MSIE 7") >= 0) {
        return 'sizeIE7';
      } else {
        return 'sizeOther';
      }
    }

    initialize();
  };

  /**
   * 実行する関数の割り当て
   *
   * @param object config
   * + string sitename サイトごとに割り当てるオブジェクト名
   * + string idPostfix
   * + string classPostfix
   * + string common
   *
   * @notice HTML内<body>のid属性、class属性に応じて $.idName.className()を呼び出す。
   * @notice 呼び出す関数:
   *   common != '':
   *     $.idName.common(); $.idName.className();
   *   common == '':
   *     $.idName();
   * @notice class属性には接尾辞が必要。
   * @notice スクリプトの最後でコール。
   *
   * @return void
   */
  $.fn.base.dispatcher = function(config) {
    var config = $.extend({
                            sitename : 'site',
                            idPostfix : '',
                            classPostfix : 'Action',
                            common : 'common'
                          }, config);
    var obj1 = $('body')[0].id + config.idPostfix;
    var obj2 = ''
    var bodyClass = $('body')[0].className.split(' ');
    for (var i = 0, len = bodyClass.length; i < len; i++) {
      if (bodyClass[i].lastIndexOf(config.classPostfix) > -1) {
        obj2 = bodyClass[i];
      }
    }

    if ($[config.sitename]) $[config.sitename][config.common]();
    if ($[config.sitename][obj1]) {
      if (config.common) {
        if ($[config.sitename][obj1][config.common]) $[config.sitename][obj1][config.common]();
        if ($[config.sitename][obj1][obj2]) $[config.sitename][obj1][obj2]();
      } else {
        if ($[config.sitename][obj1]) $[config.sitename][obj1]();
      }
    }
  };
});

