/*
 * jquery.pageslide.js
 * 
 * (c) 2011 kumagaiyusuke.
 * 
 * IE8 フェードバグあり
 * 
*/

(function ($) {

  var name_space = 'pageSlider';

  $.fn[name_space] = function(options) {


/* エラー処理 */

    // エレメントが指定されていなかったり複数選択されている場合はエラー
    if (this.length != 1) {
      throw Error('ユニークなエレメントを選択してください。(pageSlider.js)');
    }
    // 個別のid属性で識別できない要素はエラー
    if (this.attr('id').length == 0) {
      throw Error('id属性値を持つエレメントを選択してください。(pageSlider.js)');
    }


/* プライベートプロパティ */  

    var $this = this;
    
    // 共通で使用する名前
    var pageSliderID = $this.attr('id');
    
    // ページのカウント周り
    var _currentPage = 1;
    var _pageTotal = 0;

    // アニメーションとかのオプション
    var settings = $.extend({
      autoPlay : false,
      interval : 4000,
      duration : 600,
      easing : 'swing'
    }, options);

    // ページごとのコンテンツを保持する配列
    var pageHTML = [];
    
    // 自動再生に関するプロパティ
    var isAutoPlay = settings.autoPlay;
    var autoPlay;


/* パブリックメソッド */

    // ページを追加
    $this[name_space].addPage = function (htmlData) {
      
      if ( $.isArray(htmlData) ) {
        pageHTML = pageHTML.concat(htmlData);
      }
      else {
        pageHTML.push(htmlData);
      }
            
      generatePages();
    };

    // ページを削除
    $this[name_space].removePage = function (index) {
      pageHTML.splice(index,1);
      generatePages();
    };
    
    // 自動スライドを開始
    $this[name_space].play = function () {
      autoPlay = setTimeout(autoPlayLoop,settings.interval);
    };
    
    // 自動スライドを停止
    $this[name_space].stop = function () {
      clearTimeout(autoPlay);
    };


/* 初期化 */
    
    // インターフェイス用の要素を作成
    $this.html('<div id="' + pageSliderID + '-contents">' +
               '<div id="' + pageSliderID + '-pages"></div>' +
               '</div>' +
               '<div id="' + pageSliderID + '-controller">' +
               '  <div id="' + pageSliderID + '-controller-prev"><a href="#prev">Prev</a></div>' +
               '  <div id="' + pageSliderID + '-controller-pager"></div>' +
               '  <div id="' + pageSliderID + '-controller-next"><a href="#next">Next</a></div>' +
               '</div>');


/* イベント登録 */    
    
    $this.delegate('#' + pageSliderID + '-controller-prev','click',onClickPrev);
    $this.delegate('#' + pageSliderID + '-controller-next','click',onClickNext);
    $this.delegate('#' + pageSliderID + '-controller-pager a','click',onClickPager);
    
    
/* イベントハンドラ */

    // 前へボタンがクリックされたとき
    function onClickPrev(evt) {
      
      evt.preventDefault();
      
      var nextPage = getCurrentPage() - 1;
          nextPage = parsePageIndex(nextPage);
      
      changePage(nextPage);
      changePager(nextPage);
      setCurrentPage(nextPage);
      
      return false;
    }

    // 次へボタンがクリックされたとき
    function onClickNext(evt) {
      
      var nextPage = getCurrentPage() + 1;
          nextPage = parsePageIndex(nextPage);
      
      changePage(nextPage);
      changePager(nextPage);
      setCurrentPage(nextPage);
      
      return false;
    }

    // ●がクリックされたとき
    function onClickPager(evt) {
      
      var nextPage = $(evt.currentTarget).index() + 1;
          nextPage = parsePageIndex(nextPage);
      
      changePage(nextPage);
      changePager(nextPage);
      setCurrentPage(nextPage);
      
      return false;
    }


/* ゲッターセッター */

    // 現在のページ
    function getCurrentPage() {
      return _currentPage;
    }
    function setCurrentPage(num) {
      if ( typeof num != 'number' && num >= 1 && num <= getPageTotal() ) {
        throw Error('不正な値です(pageSlider.js)');
      }
      _currentPage = num;
    }
    
    // ページの合計
    function getPageTotal() {
      return _pageTotal;
    }
    function setPageTotal(num) {
      if ( typeof num != 'number' && num <= 0 ) {
        throw Error('不正な値です(pageSlider.js)');
      }
      _pageTotal = num;
    }


/* プライベートメソッド */
    
    // ページ番号を適切な値へ変換
    function parsePageIndex(index) {
      
      if (index <= 0) {
        index = getPageTotal();
      }
      else if (index > getPageTotal()) {
        index = 1;
      }
      
      return index;
    }
    
    // ページを変更する
    function changePage(nextPage) {

      // 自動再生が設定されていた場合はループを一時中断
      if (isAutoPlay) {
        $this[name_space].stop();
      }
      
      $this.find('#' + pageSliderID + '-pages').stop().animate({
        left: - 604 * (nextPage - 1)
      },{
        duration : settings.duration,
        easing : settings.easing,
        complete : function () {
          // 自動再生が設定されていた場合はループする
          if (isAutoPlay) {
            $this[name_space].play();
          }
        }
      });

    }
    
    // 現在の●を変更する
    function changePager(nextPage) {
      $this
        .find('#' + pageSliderID + '-controller-pager a').removeClass('current')
          .eq(nextPage - 1).addClass('current');
    }
    
    // 自動再生ループ
    function autoPlayLoop() {
      
      var nextPage = getCurrentPage() + 1;
          nextPage = parsePageIndex(nextPage);
      
      changePage(nextPage);
      changePager(nextPage);
      setCurrentPage(nextPage);
    }
    
    // 各ページのHTMLを生成する
    function generatePages() {

      var pages = '';
      var pager = '';
      
      // htmlになる文字列を生成
      for (var i = 0; i < pageHTML.length; i++) {
        
        var pagerClass = '';
        
        if ( (i + 1) == getCurrentPage() ) {
          pagerClass = 'current';
        } 
        
        pages += '<div class="' + pageSliderID + '-page" id="' + pageSliderID + '-page' + (i + 1) + '">' + pageHTML[i] + '</div>';
        pager += '<a href="#page' + (i + 1) + '" class="' + pagerClass + '"></a>';
        
      }
      
      $this
        // ページに応じた要素を生成
        .find('#' + pageSliderID + '-pages').html(pages)
      .end()
        .find('#' + pageSliderID + '-controller-pager').html(pager)
      .end();

      // GUIなど全体の初期化
      changePage(1);
      changePager(1);
      setCurrentPage(1);
      setPageTotal(pageHTML.length);
    }
    
    return this;

  };

})(jQuery);

