var undercover = undercover || {};
(function(exports) {
  var Blinker = function(selector, callback, interval) {
    this._element = $(selector);
    this._callback = callback;
    this._interval = interval;
  };

  Blinker.prototype.start = function(interval) {
    var that = this;
    this._loop = setInterval(function() { that._callback(that._element); }, that._interval);
  };

  Blinker.prototype.stop = function() {
    clearInterval(this._loop);
  };
  
  var DataSource = function(resource) {
    this.resource = resource;
    this.offset = 0;
    this.limit = 0;
  };

  DataSource.prototype.load = function(limit, initialOffset) {
    var that = this;
    this.limit = limit;
    this.offset = initialOffset || 0;
    var dfd = new $.Deferred();
    if (this.data) {
      setTimeout(function() { dfd.resolve(); }, 0);
    } else {
      $.ajax({url: this.resource, dataType: 'json', cache: false})
        .done(function(data) {
          if (data.status === 'success') {
            that.total = data.body.length;
            if (that.limit === 0) that.limit = that.total;
            that.data = data.body;
            dfd.resolve();
          } else {
            dfd.reject();
          }
        })
        .fail(function() {
          dfd.reject();
        });
    }
    return dfd.promise();
  };

  DataSource.prototype.getAll = function() {
    return this.data;
  };
  
  DataSource.prototype.getItem = function() {
    return this.data.slice(this.offset, this.offset + this.limit);
  };

  DataSource.prototype.getPage = function() {
    return Math.floor(this.offset / this.limit) + 1;
  };

  DataSource.prototype.prev = function() {
    this.offset = this.offset - this.limit > 0 ? this.offset - this.limit : 0;
    return this;
  };

  DataSource.prototype.next = function() {
    this.offset = this.offset + this.limit;
    return this;
  };

  DataSource.prototype.hasPrev = function() {
    return this.offset > 0;
  };

  DataSource.prototype.hasNext = function() {
    return this.offset + this.limit < this.total; 
  };

  DataSource.prototype.goTo = function(i) {
    this.offset = this.limit * (i - 1);
    return this;
  };

  var StoreSource = function(resource) {
    DataSource.call(this, resource);
  };

  StoreSource.prototype = new DataSource();
  
  StoreSource.prototype.getStore = function(id) {
    return this._nodeList[id];
  };

  //ツリーのノード部分を番地つきで返す
  StoreSource.prototype.getNodeList = function(depth) {
    var result = [];
    var parse = (function() {
      var result = {};
      return function(data, address) {
        $.each(data, function(i, item) {
          var newAddress = address + (address === '' ? '' : '-') + (i + 1);
          result[newAddress] = item;
          if (item.children) {
            parse(item.children, newAddress);
          }
        });
        return result;
      };
    })();
    //キャッシュがない場合のみツリーを解析
    if (!this._nodeList) {
      this._nodeList = parse(this.data[0].children, '');
      this.data[0].itemId = '';
    }
    if (depth === 0) {
      return this.data;
    } else {
      $.each(this._nodeList, function(i, item) {
        if (i.replace(/[^-]/g, '').length === depth - 1) {
          item.itemId = i;
          result.push(item);
        }
      });
      return result;
    }
  };

  var Renderer = function(selector, parentElem) {
    this._selector = selector;
    this._parent = parentElem;
  };
  
  Renderer.prototype.render = function(data, callback) {
    //画像がロードされるのを待つ
    var that = this
      , dfd = new $.Deferred()
      , counter;

    var $elem = $(this._selector).tmpl(data)
      , $img = $elem.find('img');
    counter = $img.length;
    if (counter > 0) {
      $img
        .bind('load', function() {
          counter--;
          if (counter === 0) dfd.resolve($elem);
        })
        .bind('error', function() {
          counter--;
          if (counter === 0) dfd.resolve($elem);
        });
    } else {
      dfd.resolve($elem);
    }
    return dfd.done(function() {
      that._parent.empty().append($elem);
    });
  };

  var utils = {
    activate: function(elem) {
      if (elem.parent('a').length === 0) {
        elem.wrap('<a href="javascript:void(0);"><a/>');
      }
    },
    deactivate: function(elem) {
      if (elem.parent('a').length > 0) {
        elem.parent('a').before(elem).remove();
      }
    },
    getQueryString: function(key) {
      var str = location.href.split('?')[1]
       , queries = {};
      if (str) {
        $.each(str.split('&'), function(i, item) {
          var i = item.indexOf('=');
          if (i > 0) queries[item.slice(0, i)] = item.slice(i + 1);
        });
      }
      return queries[key];
    }
  };

  exports.Blinker = Blinker;
  exports.DataSource = DataSource;
  exports.StoreSource = StoreSource;
  exports.Renderer = Renderer;
  exports.utils = utils;
}(undercover));

