/**
 * @name util.js
 * @fileOverview
 * @version 1.1
 * @author <a href="mailto:imai@4digit.jp">Kotaro Imai</a> @ <a href="http://hokypoky.info">HOKYPOKY.</a>
 * @description
 * <p>JavaScript Utility Library</p>
 * <p>(c) FOURDIGIT Inc. Licensed <a href="http://ja.wikipedia.org/wiki/GNU_General_Public_License">GNU General Public License</a>.</p>
 */
if(!Fourdigit) {
  /**
   * @namespace Fourdigit
   * @description
   * <p>namespace:Fourdigit</p>
   * <p>これは他のクラスなどと名前がかぶらないようにするためのものです。</p>
   */
  var Fourdigit = {}
}
(function($) {
  /**
   * @class Utility Core Class
   * @description
   * <p>FOURDIGIT Inc jQuery Plugins Core Class</p>
   * <p>ここは内部的に利用する関数が主です。</p>
   */
  Fourdigit.core = $.extend(
  /** @lends Fourdigit.core */
  {
    /**
     * 基準JS(id)のbasePathを返す
     * @function
     * @param {String}  id 基準となるJSファイルのid名
     * @param {String}  delimiter セパレートする文字列
     * @return {String}
     * @example
     * basePath("jqueryJS","common/js"); -> return path to jqueryJS(default)
     */
    basePath : (function (id,delimiter) {
      var _id = (id ? id : "JqueryJS");
      var _delimiter = (delimiter ? delimiter : "common/js");
      return document.getElementById(_id).src.split(_delimiter)[0];
    })(),
    /**
     * userAgentをbodyのクラスとして追加する
     * @function
     */
    addClassUA : function() {
      var ua = navigator.userAgent.toLowerCase();
      var _os = (
        /(x11|linux)/.test(ua)?  "linux":
        /mac/.test(ua)?      "mac":
        /win/.test(ua)?      "win":
        ""
      )
      if(_os != "") $("body").addClass(_os);
      var _browser = (
        $.browser.safari?  "safari":
        $.browser.msie?  "msie":
        $.browser.opera?  "opera":
        $.browser.mozilla?  "mozilla":
        ""
      )
      if(_browser != "") $("body").addClass(_browser);
      if(_browser == "msie") {
        var _version = (
          $.browser.version == "5.0"? "ie50":
          $.browser.version == "5.5"? "ie55":
          $.browser.version == "6.0"? "ie6":
          $.browser.version == "7.0"? "ie7":
          $.browser.version == "8.0"? "ie8":
          ""
        )
        if(_version != "") $("body").addClass(_version);
      }
    },
    /**
     * 対象のリンクをポップアップする
     * @function
     * @param {String}  src ポップアップ先のURL
     * @param {String}  windowName ウィンドウ名
     * @param {Boolean}  status メニューバーの有無
     */
    popWindow: function(src,windowName,status) {
      var _href    = (src ? src : "");
      var _isPop    = (status != null);
      var _windowName = (windowName ? windowName : "");
      if(_isPop){
        var _features = "";
        status.width?    _features += ",width="+Math.min(status.width, screen.availWidth):"";
        status.height?    _features += ",height="+Math.min(status.height, screen.availHeight-50):"";
        status.left?    _features += ",left="+status.left:"";
        status.top?      _features += ",top="+status.top:"";
        status.menubar?    _features += ",menubar="+status.menubar:
                  _features += ",menubar=no";
        status.toolbar?    _features += ",toolbar="+status.toolbar:
                  _features += ",toolbar=no";
        status.location?  _features += ",location="+status.location:
                  _features += ",location=no";
        status.status?    _features += ",status="+status.status:
                  _features += ",location=no";
        status.resizable?  _features += ",resizable="+status.resizable:
                  _features += ",resizable=yes";
        status.scrollbars?  _features += ",scrollbars="+status.scrollbars:
                  _features += ",scrollbars=yes";
        _features = _features.replace(/^,/,"");
        void(window.open(_href, _windowName, _features));
      } else {
        void(window.open(_href, _windowName, null));
      }
    },
    /**
     * ExternalInterface用
     * @return {DOMObject}
     */
    AS: function(str) { return ($.browser.msie? window[str]: document[str]); },
    /**
     * 対象の要素を含んでいるかどうかを判別
     * @function
     * @param {String}  expr CSS形式での対象要素
     * @return {Boolean}
     * @example
     * if(jQuery.hasElem("#index")){
     *  alert("#indexがあります。");
     * }else{
     *  alert("#indexがありません。");
     * }
     */
    hasElem: function (expr) { return $(expr)[0]; },
    /**
     * easyOver用イベントハンドラクラス
     * @class
     */
    easyOver: {
      /**
       * mouseover時のハンドラ
       * @function
       * @param {Event}  マウスオーバーイベント
       */
      mouseoverHandler: function (e) {
        this.src = $(this).data("ov_src");
        $(this).enablePNG();
      },
      /**
       * mouseout時のハンドラ
       * @function
       * @param {Event}  マウスオーバーイベント
       */
      mouseoutHandler: function (e) {
        this.src = $(this).data("df_src");
      },
      /**
       * click時のハンドラ
       * @function
       * @param {Event}  マウスクリックイベント
       */
      clickHandler: function (e) {
        this.src = $(this).data("on_src");
        $(this).enablePNG();
      }
    },
    /**
     * moveOpener
     * @function
     * @param {String} pFile 飛び先
     * @description
     * <p>For discussion and comments, see: http://remysharp.com/2009/01/07/html5-enabling-script/</p>
     */
    moveOpener: function (pFile){
      if(/MSIE/.test(navigator.userAgent)){
        if(typeof window.opener.name == "string"){
          opener.focus();
          void(opener.location.href = pFile);
          window.close();
        }else{
          void(window.open(pFile));
        }
      }else if(opener){
        opener.focus();
        void(opener.location.href = pFile);
        window.close();  
      }else{
        void(window.open(pFile));
      }
    },
    /**
     * auto Enable PNG
     * @function
     * CSSを解析してPNGを貼る
     */
    autoEnablePNG: function(){
      if(!$.browser.msie || $.browser.version > 6) return;
      var addonPath = "common/js/iepngfix_tilebg.js";
      $.getScript($.basePath + addonPath, function(){
        $(document.styleSheets).each(function(){
          $(this.rules).each(function(){
            var cssText = this.style.cssText.toLowerCase();
            var selector = this.selectorText;
            var isPngBg = /background.*png/.test(cssText) ? true : false;
            if(isPngBg){
              $(selector).enablePNG("common/js/iepngfix.htc");
            }
          });
        });
      });
      $("img[src$=png],input[src$=png]").enablePNG("common/js/iepngfix.htc");
    },
    /**
     * IEにHTML5用を有効にするタグを加える
     * @function
     * @description
     * <p>For discussion and comments, see: http://remysharp.com/2009/01/07/html5-enabling-script/</p>
     */
    enableHTML5: function(){
      if(!/*@cc_on!@*/0)return;
      var
        e = "abbr,article,aside,audio,canvas,datalist,details,eventsource,figure,footer,header,hgroup"+
            "mark,menu,meter,nav,output,progress,section,time,video".split(','),
        i = e.length;
      while(i--){document.createElement(e[i])}
    },
    /**
     * 要素の高さを最大値に揃える
     * @function
     */
    heightline: function(expr) {
      var maxHeight = 0;
      $(expr)
        .each(function() {
          maxHeight = Math.max(maxHeight, $(this).height())
        })
        .height(maxHeight)
      ;
    },
    /**
     * Cookie plugin
     * @function
     * @description
     * <p>Copyright (c) 2006 Klaus Hartl (stilbuero.de)<br /><a href="http://plugins.jquery.com/project/cookie" target="_blank">http://plugins.jquery.com/project/cookie</a></p>
     * <p>Dual licensed under the MIT and GPL licenses:</p>
     * <p><a href="http://www.opensource.org/licenses/mit-license.php" target="_blank">http://www.opensource.org/licenses/mit-license.php</a></p>
     * <p><a href="http://www.gnu.org/licenses/gpl.html" target="_blank">http://www.gnu.org/licenses/gpl.html</a></p>
     */
    cookie: function(name, value, options) {
      if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
          value = '';
          options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
          var date;
          if (typeof options.expires == 'number') {
            date = new Date();
            date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
          } else {
            date = options.expires;
          }
          expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // CAUTION: Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
      } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
          var cookies = document.cookie.split(';');
          for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
              cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
              break;
            }
          }
        }
        return cookieValue;
      }
    },
    /**
     * status
     * @class
     * @description
     * <p>動的にステータスをつける拡張</p>
     */
    status: {
      /**
       * hover時に .hoverクラスをつける
       * @function
       * @param {String}  expr selectorexpr
       * @param {String}  _class 付与するクラス
       */
      hover: function(expr, _class) {
        if(typeof value != 'undefined') _class = "hover";
        $(expr)
          .live("mouseover",function(){
            $(this).addClass(_class);
          })
          .live("mouseout",function(){
            $(this).removeClass(_class);
          })
        ;
      },
      /**
       * 子要素の一番最初にクラスをつける
       * @function
       * @param {String}  expr selectorexpr
       * @param {String}  _class 付与するクラス
       */
      first: function(expr, _class) {
        if(typeof value != 'undefined') _class = "first";
        $(expr).each(function(){
          $(this).find(">:first").addClass(_class);
        });
      },
      /**
       * 子要素の一番最後にクラスをつける
       * @function
       * @param {String}  expr selectorexpr
       * @param {String}  _class 付与するクラス
       */
      last: function(expr, _class) {
        if(typeof value != 'undefined') _class = "last";
        $(expr).each(function(){
          $(this).find(">:last").addClass(_class);
        });
      }
    }
  });
  /**
   * @class Utility Utility Class
   * @description
   * <p>FOURDIGIT Inc jQuery Plugins Utility Class</p>
   * <p>ここはjQueryオブジェクトに対して機能追加されるプラグイン関数部分です。</p>
   */
  Fourdigit.util = $.fn.extend(
  /** @lends Fourdigit.util */
  {
    /**
     * IE5.5/6にPNGを効かせるpngfix用filter
     * @function
     * @return {jQuery}  jQueryオブジェクトを返すのでそのままチェーンします。
     * @example  
     * jQuery("img[src$=png],img.png").enablePNG();
     */
    enablePNG: function(htcPath){
      if($.browser.msie && $.browser.version <= 6) {
        this.each(function(){
          $(this).css("behavior", "url("+$.basePath+htcPath+")");
        });        
      }
      return this;
    },
    /**
     * IE6/5+ winXP SP2 KB912945の修正による白枠対策
     * @function
     * @return {jQuery}
     * @example  
     * jQuery("object, embed").enableFlash();
     */
    enableFlash: function(){
      if($.browser.msie){
        this.each(function () {
          this.removeAttribute('data');
          this.outerHTML += "";
        });
      }
      return this;
    },
    /**
     * 対象要素のイメージをオーバーした際に画像のパスをfname.extからfname_ov.extにする
     * @function
     * @return {jQuery}  jQueryオブジェクトを返すのでそのままチェーンします。
     * @example
     * jQuery("img.ahover, .ahoverArea img").easyOver();
     */
    easyOver: function(hasOn){
      var preImgArrOv = new Array();
      var preImgArrOn = new Array();
      var $imggrp = this;
      $imggrp
        .each(function(){
          var $this = $(this);
          var src = this.src;
          var isov = src.substring(0,src.lastIndexOf('.'));
          if( !/_(ov|on|off)$/.test(isov) ) {
            var ftype = src.substring(src.lastIndexOf('.'), src.length);
            var df_src = src;
            var ov_src = src.replace(ftype, '_ov'+ftype);
            preImgArrOv.push(new Image());
            preImgArrOv[preImgArrOv.length-1].src = ov_src;
            
            $this
              .data({
                df_src: df_src,
                ov_src: ov_src,
                on_src: ov_src
              });
              if(hasOn){
                var on_src = src.replace(ftype, '_on'+ftype);
                preImgArrOn.push(new Image());
                preImgArrOn[preImgArrOn.length-1].src = on_src;
                $this.data("on_src", on_src );
              }
            $this
              .bind("mouseover", $.easyOver.mouseoverHandler)
              .bind("mouseout", $.easyOver.mouseoutHandler)
              .bind("mouseon", function(){
                $imggrp
                  .each(function(){
                    $(this).attr("src", $(this).data("df_src"));
                  })
                  .bind("mouseover", $.easyOver.mouseoverHandler)
                  .bind("mouseout", $.easyOver.mouseoutHandler)
              })
              .bind("mouseon", $.easyOver.clickHandler)
              .bind("mouseon", function(){
                $this.removeEasyOver()
              })
            .end();
            
          }
        })
      ;
      return this;
    },
    /**
     * 対象要素のイメージのeasyOverを削除
     * @function
     * @return {jQuery}  jQueryオブジェクトを返すのでそのままチェーンします。
     * @example
     * jQuery("#trigger").click(function(){
     *   jQuery(this).find("img.ahover").removeEasyOver()
     * });
     */
    removeEasyOver: function (){
      this.each(function(){
        $(this)
          .unbind("mouseover",$.easyOver.mouseoverHandler)
          .unbind("mouseout",$.easyOver.mouseoutHandler)
        .end();
      });
      return this;
    },
    /**
     * 対象要素のリンクをポップアップにする
     * @function
     * @return {jQuery}  jQueryオブジェクトを返すのでそのままチェーンします。
     * @example
     * jQuery("a.commonPop").easyPop();
     * <strong>HTML</strong>
     * きちんとした定義
     * &lt;a href="someLink" class="commonPop" target="_blank" rel="width:500,height:300"%gt;SOME LINK%lt;a%gt;
     * 略 - widthとheightしか指定できません
     * &lt;a href="someLink" class="commonPop" target="_blank" rel="500,300"%gt;SOME LINK%lt;a%gt;
     */
    easyPop: function(){
      this.each(function(){
        this.target = "";
        var rel = {};
        if(!/:/.test(this.rel)){
          var relArr = this.rel.split(",");
          if(relArr[1]){
            rel["width"] = relArr[0];
            rel["height"] = relArr[1];
          }else{
            rel["width"] = relArr[0];
            rel["height"] = relArr[0];          
          }
        }else{
          if(!this.rel) {
            rel = { width : "750", height : "800" }
          }else{
            var relArr = this.rel.split(",");
            if(this.rel.split(":")){
              for (var i = 0; i < relArr.length; i++) {
                var _key = relArr[i].split(":")[0];
                var _val = relArr[i].split(":")[1];
                rel[_key] = _val;
              }
            }
          }        
        }
        $(this).click(function(){
          var wname = (rel["wname"]? rel["wname"]: "");
          $.popWindow(this.href,wname,rel);
          return false;
        });
      })
      return this;
    },
    /**
     * 対象要素のリンクもGoogleAnalyticsに情報を送る
     * @function
     * @return {jQuery}  jQueryオブジェクトを返すのでそのままチェーンします。
     * @example
     * jQuery("a").blankLogToGoogle();
     * jQuery("a['target'='_blank']").blankLogToGoogle();
     */
    blankLogToGoogle: function() {
      this.each(function(){
        var expr = new RegExp("(.*)://(/?)(.*?)/");
        var h = this.href;
        var hArr = h.match(expr);
        var l = location.href;
        var lArr = l.match(expr);
        if(hArr[0] != lArr[0]) {
          var str = h.replace(/\?/g, "%3F");
          $(this).click(
            function(){
              pageTracker._trackPageview('/blank/?'+str);
            }
          );
        }
      });
      return this;
    },
    /**
     * 対象要素がページないリンクだった場合、イージングでスクロールするようにする
     * @function
     * @return {jQuery} jQueryオブジェクトを返すのでそのままチェーンします。
     * @example
     * jQuery("a[href*=#]").smoothScroll();
     */
    smoothScroll: function (speed) {
        var lh = decodeURIComponent(location.href);
        var pagePath = /\?/.test(lh)? lh.split('?')[0]: /#/.test(lh)? lh.split('#')[0]: lh;
        var scrollInt;
        this.each(function(){
          var th = decodeURIComponent(this.href);
          var actX, actY, tarY = 0, tarX = 0;
          speed = (!speed? 6: speed == "fast"? 3: speed == "normal"? 6: speed == "slow"? 12: speed);
          var setScroll = function (tarX,tarY,anc) {
            actX += (tarX - actX) / parseInt(speed);
            actY += (tarY - actY) / parseInt(speed);
            if(Math.abs(tarX - actX) < 1 && Math.abs(tarY - actY) < 1){
              clearInterval(scrollInt);
              scrollTo(Math.round(tarX),Math.round(tarY));
              location.hash = "#"+anc;
              scrollTo(Math.round(tarX),Math.round(tarY));
            }else {
              scrollTo(Math.round(actX), Math.round(actY));
            }
          }
          var anc = th.split('#')[1];
          if(!anc) return;
          if( /#/.test(th)  && th.match(pagePath) && $('#'+anc)[0] ){
            $(this).click(function (){
              var tarObj = $('#'+anc);
              tarX = ($(document).width() > tarObj.position().left + $(window).width())
                  ? tarObj.position().left
                  : $(document).width() - $(window).width();
              tarY = ($(document).height() > tarObj.position().top + $(window).height())
                  ? tarObj.position().top
                  : $(document).height() - $(window).height();
              actX = $(document).scrollLeft();
              actY = $(document).scrollTop();
              clearInterval(scrollInt);
              scrollInt = setInterval(function(){setScroll(tarX,tarY,anc)}, 20);
              return false;
            });
          }
        });
        //stop when mousewheel
        var wheel = function () {clearInterval(scrollInt);}
        if (window.addEventListener) window.addEventListener('DOMMouseScroll', wheel, false);
        window.onmousewheel = document.onmousewheel = wheel;
        return this;
    },
    /**
     * 対象要素をスクロールに追従するようにする(CSSでabsoluteにしている必要あり)
     * @function
     * @param {String}  stopper  スクロールを止める要素のid名
     * @param {Number|String}  speed  スクロールのスピード。
     * @return {jQuery}  jQueryオブジェクトを返すのでそのままチェーンします。
     * @example
     * jQuery("#fix").fixPosition();  // normalと同じ
     * jQuery("#fix").fixPosition("slow");
     * jQuery("#fix").fixPosition("normal");
     * jQuery("#fix").fixPosition("fast");
     * jQuery("#fix").fixPosition(12);  // slowと同じ
     * jQuery("#fix").fixPosition(6);  // normalと同じ
     * jQuery("#fix").fixPosition(3);  // fastと同じ
     * jQuery("#fix").fixPosition(100);  // すごく遅いのでオススメしない
     */
    fixPosition: function (stopper,speed) {
      speed = (!speed? 6: speed == "fast"? 3:  speed == "normal"? 6: speed == "slow"? 12: speed);
      var fixScrollTop     = function () { return $(document).scrollTop()};
      var fixScrollBottom  = function () { return $(document).scrollTop()+$(document).height()};
      this.each(function(){
        var obj = this;
        var offsetY    = function(){ return $(obj).offset().top };
        var posY    = function(){ return $(obj).position().top };
        var boxHeight  = $(obj).height();
        var topLimit  = posY();
        var bottomLimit;
        var fix_idle  = 10;
        var intervalID;
        var easeScroll = function (stopper) {
          if (fix_idle <= 0) {
            var bottom = offsetY() + boxHeight;
            var tar = Math.max(fixScrollTop(), topLimit);
            if ( stopper && ( tar + boxHeight ) > bottomLimit ) {
              tar =  bottomLimit -　boxHeight;
            }
            var nPos = (tar - offsetY()) / speed + posY();
            obj.style.top = nPos + 'px';
          } else {fix_idle--; }
        };
        if(document.getElementById(stopper)){
          var stopObj = document.getElementById(stopper);
          bottomLimit = $(stopObj).position().top;
          intervalID = setInterval(function(){easeScroll("stopper")}, 20);
        }else {
          intervalID = setInterval(function(){easeScroll()}, 20);
        }
        /**
         * @function
         * @ignore
         */
        document.onscroll = function() { fix_idle = 10; }
      });
      return this;
    },
    /**
     * openerが存在したらopenerのURLを、存在しなかったら自身のURLを対象要素のhref変える。
     * @function
     * @return {jQuery}  jQueryオブジェクトを返すのでそのままチェーンします。
     * @example
     * jQuery("a.moveOpener").moveOpener();
     */
     moveOpener: function(){
       this.each(function(){
          var $this = $(this);
          $this.attr("dhref",$this.attr("href"));
          $this.click(function(){
            moveOpener($this.attr("dhref"));
            return false;
          });
       });
       return this;
     },
    /**
     * 要素の高さを最大値に揃える
     * @function
     * @param {String} childExpr スコープ内で比較する子要素を指定
     * @param {jQuery} jQueryオブジェクトを返すのでそのままチェーンします。
     * @example
     * $(".separator").heightline(".box"); // .separator毎に.boxを比較、最大高さで揃える
     */
    heightline: function(childExpr) {
      var $this = $(this);
      var $childExpr = $this.find(childExpr)
      var exec = function(){
        $childExpr.css("height", "auto");
        $.heightline($childExpr);
      };
      $(window).bind("styleswitch", exec);
      exec();
      return this;
    }
  });
})(jQuery);
