var CONFIG = CONFIG || {};
CONFIG.SEARCH_TIMEOUT = 300;
CONFIG.SEARCH_MIN_LENGTH = 0;

// 拡張表示
//   標準［1］=Etc列なし
//   拡張［2］=Etc列あり
var DISPLAY_TYPE_ETC = 2;


// 20190719 delete[nishino] start
/**
 * メーカー情報
 *
 * @param arg
 * @constructor
 */

// var MakerModel = function MakerModel(arg) {
//   this.data = arg.data;
// };

// MakerModel.prototype.find = function find(condition) {
//   if (!condition) {
//     return this.data;
//   }
//
//   condition = _.merge({
//     maker_cd: null
//   }, condition);
//
//   return _.filter(this.data.collection, function (item) {
//     if (_.get(item, 'maker-cd') != condition.maker_cd) {
//       return false;
//     }
//
//     return true;
//   });
// };
// 20190719 delete[nishino] end

/**
 * マニュアル情報
 *
 * @param arg
 * @constructor
 */
var ManualModel = function ManualModel(arg) {
  this.data = arg.data;
};

/*
 * マニュアルデータ取得
 *
 * @returns {*}
 */
ManualModel.prototype.find = function find(condition) {
  var self = this;

  // 検索条件が未指定の場合、全てを取得
  if (!condition) {
    return this.data.collection;
  }

  // 初期値とマージ
  condition = _.merge({
    cpu_series: null,
    cpu: null,
    link_if: null,
    com_method: null,
    driver_nm: null  // 20190719 add[nishino]
  }, condition);

  // 絞り込み
  return _.filter(this.data.collection, function (item) {
    if (!self.compare(item['cpu-series'], condition.cpu_series)) {
      return false;
    }

    if (!self.compare(item['cpu'], condition.cpu)) {
      return false;
    }

    if (!self.compare(item['link-if'], condition.link_if)) {
      return false;
    }

    if (!self.compare(item['com-method'], condition.com_method)) {
      return false;
    }

    // 20190719 add[nishino] start
    if (!self.compare(item['driver'], condition.driver_nm)) {
      return false;
    }
    // 20190719 add[nishino] end

    // クエリ文字列「driver」による絞り込み
    // - 4つの項目の内いずれかに含まれればTRUE
    if (!self.compare(item['jump']['url'], condition.driver)
      && !self.compare(item['settings']['url'], condition.driver)
      && !self.compare(item['cable-diagram']['url'], condition.driver)
      && !self.compare(item['support-device']['url'], condition.driver)) {
      return false;
    }

    return true;
  });
};

/**
 * リストを取得
 * @param {string} propName プロパティ名
 * @returns {*}
 */
ManualModel.prototype.findList = function findList(propName) {
  return _(this.data.collection)
    .map(function (item) {
      return item[propName];
    })
    .uniq()
    .value();
};

/**
 * 比較
 *
 * @param value
 * @param condition
 * @returns {boolean}
 */
ManualModel.prototype.compare = function compare(value, condition) {
  if (_.isString(condition) &&
    !_.includes(_.toLower(zenkakuToHankaku(value)), _.toLower(zenkakuToHankaku(condition)))) {
    return false;
  }

  return true;
};

var ManualView = function ManualView(arg) {
  this.$el = arg.$el;
  this.template = arg.template;
  this.compiled = _.template(this.template);
};

/**
 * マニュアルデータ表示
 *
 * @param collection マニュアルデータ
 * @param etcVisible true: 拡張項目を表示する false: 拡張項目を表示しない
 */
ManualView.prototype.render = function render(collection, etcVisible) {
  var cols;

  // 行スパンを初期化
  cols = [
    {
      key: 'cpu-series',
      rowspan: 0,
      attrs: { 'class': 'js-hl-target-cpu_series' }
    }, {
      key: 'cpu',
      rowspan: 0,
      attrs: { 'class': 'js-hl-target-cpu' }
    }, {
      key: 'link-if',
      rowspan: 0,
      attrs: { 'class': 'js-hl-target-link_if' }
    }, {
      key: 'com-method',
      rowspan: 0,
      attrs: { 'class': 'js-hl-target-com_method' }
    }, {
      key: 'driver',
      rowspan: 0,
      attrs: { 'class': 'js-hl-target-driver' } // 20190719 add[nishino]
    }, {
      key: 'etc',
      rowspan: 0,
      attrs: {}
    }, {
      key: 'link',
      rowspan: 0,
      attrs: {}
    }
  ];

  // ジャンプ先URLを追加
  collection = _.map(collection, function (item) {
    return _.merge(item, {
      link: makeLinkUrl(item)
    });
  });

  var trList = [];
  _.forEach(collection, function (value, key) {
    var current = value,
      remain = _.slice(collection, key + 1), // 未処理のデータ
      tdList = [];

    for (var i = 0, l = cols.length; i < l; i++) {
      if (cols[i].rowspan > 0) {
        continue;
      }

      switch (cols[i].key) {
        case 'cpu-series':
        case 'cpu':
        case 'link-if':
        case 'com-method':
        case 'driver':
          cols[i].rowspan = countRowSpan(['cpu-series', cols[i].key], current, remain);
          tdList.push(createTdHtml(current[cols[i].key], cols[i].rowspan, cols[i].attrs));
          break;
        case 'etc':
          if (etcVisible) {
            cols[i].rowspan = countRowSpan(['cpu-series', cols[i].key], current, remain);
            tdList.push(createTdHtml(current[cols[i].key], cols[i].rowspan));
          }
          break;
        case 'link':
          cols[i].rowspan = countRowSpan(['cpu-series', cols[i].key], current, remain);
          tdList.push(createDetBoxHtml(current[cols[i].key], cols[i].rowspan));
          break;
        default:
          break;
      }
    }

    // 行を表のフラグメントに追加
    trList.push([
      '<tr>',
      tdList.join(''),
      '</tr>'
    ].join(''));

    // 行スパンをデクリメント
    _.each(cols, function (value, key) {
      cols[key].rowspan--;
    });
  });

  this.$el.html(trList.join(''));
  $(window).trigger('render');
};

var App = function App(arg) {
  this.$searchForm = arg.$searchForm;
  // this.makerModel = arg.makerModel; // 20190719 delete[nishino]
  this.manualModel = arg.manualModel;
  this.manualView = arg.manualView;
};

/**
 * 初期化
 */
App.prototype.initialize = function initialize() {
  var condition, $form;

  // 20190719 delete[nishino]
  // this.maker = this.makerModel.find({ maker_cd: params.maker_cd })[0];
  // 20190719 add[nishino]
  this.maker = makerData;


  //------------------------------------------------
  // 検索ボックスを初期化
  //------------------------------------------------
  // Series
  this.cpuSeriesView = new AutoCompleteView({
    $el: $('[name=cpu_series]'),
    source: []
  }).initialize();

  // CPU
  this.cpuView = new AutoCompleteView({
    $el: $('[name=cpu]'),
    source: []
  }).initialize();

  // Link I/F
  this.linkIfView = new AutoCompleteView({
    $el: $('[name=link_if]'),
    source: []
  }).initialize();

  // Communication Method
  this.comMethodView = new AutoCompleteView({
    $el: $('[name=com_method]'),
    source: []
  }).initialize();

  // 20190719 add[nishino] start
  // Driver
  this.driverView = new AutoCompleteView({
    $el: $('[name=driver_nm]'),
    source: []
  }).initialize();
  // 20190719 add[nishino] end

  // メーカー名を表示
  $('.js-maker-nm').text(_.get(this.maker, 'maker-nm', ''));

  // 改修 中江 20170612 delete start
  // 拡張表示タイプが「表示」の場合は「Other」列を非表示
  //this.hasEtc =  (_.get(this.maker, 'display-type-' + params.type) == DISPLAY_TYPE_ETC);
  // 改修 中江 20170612 delete end
  // 改修 中江 20170612 add start
  var displayType = _.get(this.maker, 'display-type');
  var targetStartPosition = params['port-type-flg'] - 1;
  var targetDisplayType = displayType.slice(targetStartPosition, targetStartPosition + 1);

  this.hasEtc = (targetDisplayType == DISPLAY_TYPE_ETC);
  // 改修 中江 20170612 add end

  if (!this.hasEtc) {
    $('.js-col-etc').remove();
  }

  // 検索条件を読み込み
  condition = this.loadCondition();

  $form = this.$searchForm;
  // 検索条件を復帰
  _.forEach(condition, function (val, key) {
    $form.find('[name=' + key + ']').val(val);
  });

  // driverパラメータをFORMに追加
  this.$searchForm.find('[name=driver]').val(params.driver);
  // driver_nmパラメータをFORMに追加
  this.$searchForm.find('[name=driver_nm]').val(params.driver_nm);

  // 検索処理を実行
  this.search();
};

/**
 * 検索条件を取得
 *
 * @returns {*}
 */
App.prototype.getCondition = function getCondition() {
  return this.$searchForm.serializeObject();
};

/**
 * ハイライト処理を実行
 */
App.prototype.highlight = function highlight(condition) {
  $('.js-hl-target-cpu_series').highlight(condition.cpu_series);
  $('.js-hl-target-cpu').highlight(condition.cpu);
  $('.js-hl-target-link_if').highlight(condition.link_if);
  $('.js-hl-target-com_method').highlight(condition.com_method);
  $('.js-hl-target-driver').highlight(condition.driver_nm); // 20190719 add[nishino]
};

/**
 * 検索条件を読み込み
 *
 * @returns {*}
 */
App.prototype.loadCondition = function loadCondition() {
  return DB.get('plc_detail');
};

/**
 * 検索条件を保存
 *
 * @param condition
 */
App.prototype.saveCondition = function saveCondition(condition) {
  DB.set('plc_detail', condition);
};

/**
 * 検索処理を実行
 */
App.prototype.search = function search() {
  var condition, manualData;

  condition = this.getCondition();
  this.saveCondition(condition);

  manualData = this.manualModel.find(condition);
  this.manualView.render(manualData, this.hasEtc);

  // 検索ボックスの検索ソースを更新
  var filtered = new ManualModel({ data: { collection: manualData } });
  app.cpuSeriesView.update(filtered.findList('cpu-series'));
  app.cpuView.update(filtered.findList('cpu'));
  app.linkIfView.update(filtered.findList('link-if'));
  app.comMethodView.update(filtered.findList('com-method'));
  app.driverView.update(filtered.findList('driver')); // 20190719 add[nishino]

  this.highlight(condition);
};

var app;
$(function () {
  app = new App({
    $searchForm: $('form'),
    // makerModel: new MakerModel({ data: makerData }),  // 20190719 delete[nishino]
    manualModel: new ManualModel({ data: data }),
    manualView: new ManualView({
      $el: $('table').find('tbody'),
      template: $('#template').text()
    })
  });

  // 初期化
  app.initialize();

  // 検索条件が変更されたときに更新
  $('.js-condition')
    .observeUpdate(CONFIG.SEARCH_TIMEOUT, CONFIG.SEARCH_MIN_LENGTH)
    .bind('change update', function () {
      app.search();
    });

  // 検索条件をリセット
  $(document).on('click', '.js-btn-reset', function (e) {
    e.preventDefault();
    $('.js-condition').val('');
    app.search();
  });

  // FORMの送信を抑止
  $(document).on('submit', 'form', function (ev) {
    ev.preventDefault();
  });

  // リンクにマウスオーバーした場合, リンクにフォーカスを当てる
  $(document).on('mouseover', '.js-focusable', function () {
    $(this).trigger('focus');
  });
});

/**
 * 比較元データと比較先データの値が全て一致しているか
 *
 * @param item 比較元データ
 * @param target 比較先データ
 * @param keys 比較キー
 * @returns {boolean}
 */
function isSameRow(item, target, keys) {
  var key;

  // 比較元と比較先の比較キーに該当する値を全て比較
  for (var i = 0, l = keys.length; i < l; i++) {
    key = keys[i];

    if (item[key] !== target[key]) {
      return false;
    }
  }

  return true;
}

/**
 * 行スパンをカウント
 *
 * @param key
 * @param value
 * @param remain
 * @returns {number}
 */
function countRowSpan(keys, current, remain) {
  var count = 1;

  // 切り替わるタイミングを取得
  _.forEach(remain, function (item) {
    if (isSameRow(current, item, keys)) {
      count++;
    } else {
      return false;
    }
  });

  return count;
}

/**
 * TD要素を生成（ジャンプ先）
 *
 * @param url
 * @param rowspan
 * @returns {*}
 */
function createDetBox(url, rowspan) {
  var $td = $('<td/>');
  $td.attr('rowspan', rowspan);
  $td.attr('class', 'detbox');

  var $a = $('<a/>');
  $a.attr({
    'class': 'js-focusable',
    href: url,
    target: '_blank'
  });

  var $p = $('<p/>');
  $p.text('Details');

  $a.append($p);
  $td.append($a);

  return $td[0];
}

/**
 * TD要素HTMLを生成（ジャンプ先）
 * @param url
 * @param rowspan
 * @returns {string}
 */
function createDetBoxHtml(url, rowspan) {
  return [
    '<td rowspan="{{ROWSPAN}}" class="detbox">'.replace('{{ROWSPAN}}', rowspan),
    '<a class="js-focusable" href="{{HREF}}" target="_blank">'.replace('{{HREF}}', url),
    '<p>Details</p>',
    '</a>',
    '</td>'
  ].join('');
}

/**
 * TD要素を生成
 *
 * @param text
 * @param rowspan
 * @returns {*}
 */
function createTd(text, rowspan, attrs) {
  var $td = $('<td/>'), attrs = attrs || {};
  attrs = $.extend({ rowspan: rowspan }, attrs);
  $td.attr(attrs);
  $td.text(text);

  return $td[0];
}

/**
 * TD要素HTMLを生成
 * @param text
 * @param rowspan
 * @param attrs
 * @returns {string}
 */
function createTdHtml(text, rowspan, attrs) {
  attrs = $.extend({ rowspan: rowspan }, attrs);
  var attrsText = _(attrs).map(function (v, k) {
    return [ k, '"' + _.escape(v) + '"' ].join('=');
  }).value().join(' ');

  return [
    '<td {{ATTRS}}>'.replace('{{ATTRS}}', attrsText),
    _.escape(text),
    '</td>'
  ].join('');
}

/**
 * ジャンプ先URLを生成
 *
 * @param item
 * @returns {string}
 */
function makeLinkUrl(item) {
  return [
    '../../en/device/detail/' + _.toString(_.get(item, 'jump.url')),
    '&param1=' + _.toString(_.get(item, 'settings.url')),
    '&param2=' + _.toString(_.get(item, 'cable-diagram.url')),
    '&param3=' + _.toString(_.get(item, 'support-device.url'))
  ].join('');
}







(function($){
    $(function(){
      $('.detable').css('top', $('.content-header').outerHeight());
      fixTableThead('.detable');
    });
})(jQuery);
