/**
 * @fileoverview  TwitterUserTimelineクラス
 * @author        <a href="http://s2works.homeunix.net/">s2works</a>
 * @version       1.0
 */

/**
 * @constant
 */
// user_timelineに指定できるcountの最大値
TwitterUserTimeline.COUNT_MAX = 200;

/**
 * コンストラクタ
 * @class Twitterのユーザータイムラインを表示するクラス
 * @constructor
 * @param {String}  name                Twitterのユーザー名
 * @param {Boolean} ignoreReply         他のユーザーへの返信を表示するか
 * @param {jQuery}  result              取得した内容を表示するjQueryオブジェクト
 * @param {String}  element             各ツィートを入れる要素名
 * @param {Number}  [limit=10]          表示する最大数
 * @param {Number}  [reloadInterval=60] リロード間隔(秒)
 */
function TwitterUserTimeline(name, ignoreReply, result, element, limit, reloadInterval) {
  if (limit == undefined) limit = 10;
  if (reloadInterval == undefined) reloadInterval = 60;

  this._timerId = null;
  this.name = name;
  this.ignoreReply = ignoreReply;
  this.result = result;
  this.element = element;
  this.limit = limit;
  this.reloadInterval = reloadInterval;
}

/**
 * 実行する
 * @public
 */
TwitterUserTimeline.prototype.execute = function() {
  this._load();
}

/**
 * 停止する
 * @public
 */
TwitterUserTimeline.prototype.stop = function() {
  if (this._timerId != null) {
    clearTimeout(this._timerId);
    this._timerId = null;
  }
  this._initialize();
}

/**
 * 初期化する
 * @private
 */
TwitterUserTimeline.prototype._initialize = function() {
  this._timerId = null;
  this.name = null;
  this.ignoreReply = null;
  this.result = null;
  this.element = null;
  this.limit = null;
  this.reloadInterval = null;
}

/**
 * HTTPステータスコードを表示する
 * @private
 * @param {XMLHttpRequest}  XMLHttpRequest  XMLHttpRequest
 */
TwitterUserTimeline.prototype._showHttpStatus = function(XMLHttpRequest) {
  var messages = {
    301 : "301 Moved Permanently",
    304 : "304 Not Modified",
    307 : "307 Temporary Redirect",
    400 : "400 Bad Request",
    401 : "401 Unauthorized",
    402 : "402 Payment Required",
    403 : "403 Forbidden",
    404 : "404 Not Found",
    405 : "405 Method Not Allowed",
    406 : "406 Not Acceptable",
    407 : "407 Proxy Authentication Required",
    408 : "408 Request Timeout",
    409 : "409 Conflict",
    410 : "410 Gone",
    411 : "411 Length Required",
    412 : "412 Precondition Failed",
    413 : "413 Request Entity Too Large",
    414 : "414 Request-URI Too Long",
    415 : "415 Unsupported Media Type",
    416 : "416 Requested Range Not Satisfiable",
    417 : "417 Expectation Failed",
    418 : "418 I'm a teapot",
    422 : "422 Unprocessable Entity",
    423 : "423 Locked",
    424 : "424 Failed Dependency",
    426 : "426 Upgrade Required",
    500 : "500 Internal Server Error",
    501 : "501 Not Implemented",
    502 : "502 Bad Gateway",
    503 : "503 Service Unavailable",
    504 : "504 Gateway Timeout",
    505 : "505 HTTP Version Not Supported",
    506 : "506 Variant Also Negotiates",
    507 : "507 Insufficient Storage",
    509 : "509 Bandwidth Limit Exceeded",
    510 : "510 Not Extended"
  };

  this.result.text(messages[XMLHttpRequest.status]);
}

/**
 * タイマーをセットする
 * @private
 */
TwitterUserTimeline.prototype._timer = function() {
  var self = this;
  this._timerId = setTimeout(function(){ self._load(); }, this.reloadInterval * 1000);
}

/**
 * user_timelineを取得する
 * @private
 */
TwitterUserTimeline.prototype._load = function() {
  var self = this;
  var url = 'http://twitter.com/statuses/user_timeline/' + this.name + '.json';

  var count = this.limit * 2;
  if (count > this.COUNT_MAX) count = this.COUNT_MAX;

  $.ajax({
    dataType : 'jsonp',
    url : url,
    data: {
      'count' : count.toString()
    },
    success : function (data, textStatus) {
      self.result.empty();

      var i = self.limit;
      $.each(data, function(index, item) {
        if (self.ignoreReply && item.in_reply_to_user_id) return true;

        $('<' + self.element + '/>')
          .append(self._formatDateTime(item.created_at) + ' ' + self._createLink(item.text))
          .appendTo(self.result);

        return (--i != 0);  // false -> break each
      });
      self._timer();
    },
    error : function(XMLHttpRequest, textStatus, errorThrown) {
      self._showHttpStatus(XMLHttpRequest);
    }
  });
}

/**
 * URLと返信(@name)にリンクを張る
 * @private
 * @param {String}  text  リンクを張るテキスト
 * @return  リンクを張ったHTML
 * @type    String
 */
TwitterUserTimeline.prototype._createLink = function(text) {
  var html = text.replace(/((https?|s?ftp|ssh)\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!])/g,
    function(url) {
      return '<a href="' + url + '">' + url + '</a>'
    }).replace(/\B@([_a-z0-9]+)/ig,
    function(name) {
      return name.charAt(0) + '<a href="http://www.twitter.com/' + name.substring(1) + '">' + name.substring(1) + '</a>'
    });
  return html;
}

/**
 * 日時の書式を変更
 * @private
 * @param {String}  dateTimeString  書式を変更する日時文字列
 * @return  書式を変更した日時文字列
 * @type    String
 */
TwitterUserTimeline.prototype._formatDateTime = function(dateTimeString) {
  var a = dateTimeString.split(' ');
  var UTCDateString = a[1] + ' ' + a[2] + ', ' + a[5] + ' ' + a[3];
  var milliseconds = Date.parse(UTCDateString);
  milliseconds = milliseconds - ((new Date()).getTimezoneOffset() * 60 * 1000);

  var d = new Date(milliseconds);

  var year = this._fillZero(d.getFullYear(), 4);
  var month = this._fillZero(d.getMonth() + 1, 2);
  var date = this._fillZero(d.getDate(), 2);
  var hours = this._fillZero(d.getHours(), 2);
  var minutes = this._fillZero(d.getMinutes(), 2);

  return year + '-' + month + '-' + date + ' ' + hours + ':' + minutes;
}

/**
 * 指定桁まで0で埋める
 * @private
 * @param {Number}  number  ゼロ埋めする数値
 * @param {Number}  digit   桁数
 * @return  ゼロ埋めした数値
 * @type    String
 */
TwitterUserTimeline.prototype._fillZero = function(number, digit) {
  var result = parseInt(number).toString();

  while (result.length < digit) {
    result = '0' + result;
  }

  return result;
}
