var ROWS = 10; // 1ページあたりに何件表示するか
var PAGE_RANGES = 5; // pagination で現在ページを中心に何個のリンクを表示するか
var SCROLL_PARAM = 15; // scroll の速度（1から100の整数）
var jobs = new Array();
var list = new Array();
var hasEnoughSalary     = function(job) { return true; };
var hasEnoughEmploytype = function(job) { return true; };
var hasEnoughPubdate    = function(job) { return true; };

/* truncate */
String.prototype.truncate = function(len, truncation){
  len = len || 30;
  truncation = truncation === undefined ? '…' : truncation;
  return this.length > len ?
    this.slice(0, len - truncation.length) + truncation : this;
};

/* scroll to ancher */
function scroll(id){
    bytefx.scroll(document.getElementById(id), SCROLL_PARAM);
}

/* convert New Line --> br tag */
$.fn.output = function(){
  return this.text().replace("\n", "<br />");
}

/* yyyy/mm/dd 形式の文字列を Date オブジェクト型に変換 */
function toDate(str){

  if ( !str || str.length < 1 ) return null;

  ms = str.match(/(\d+)\/(\d+)\/(\d+)/);
  if ( !ms || ms.length != 4) return null;
  y = parseInt(ms[1]);
  m = parseInt(ms[2]);
  d = parseInt(ms[3]);

  date = new Date(y, m - 1, d);

  return date;

}

/* called when any pudate is clicked */
function clkPubdate(key){

  if(key < 0 || key > 4) return false; // out of range

  var condf;

  var curr = new Date();
  curr.setHours(0);
  curr.setMinutes(0);
  curr.setSeconds(0);
  curr.setMilliseconds(0);
  var today = curr.valueOf();
  var bef3d = curr.valueOf() - (1000 * 60 * 60 * 24 * 3);
  var bef7d = curr.valueOf() - (1000 * 60 * 60 * 24 * 7);
  var bef1m = curr.valueOf() - (1000 * 60 * 60 * 24 * 31);

  switch(key){
    case 0:
      condf = 
        function(x) {
          var pubdate = toDate(x);
          return ( pubdate ? ( pubdate.valueOf() >= today ) : true );
        };
      break;
    case 1:
      condf =
        function(x) {
          var pubdate = toDate(x);
          return ( pubdate ? ( pubdate.valueOf() >= bef3d ) : true );
        };
      break;
    case 2:
      condf =
        function(x) {
          var pubdate = toDate(x);
          return ( pubdate ? ( pubdate.valueOf() >= bef7d ) : true );
        };
      break;
    case 3: // 31日前の
      condf =
        function(x) {
          var pubdate = toDate(x);
          return ( pubdate ? ( pubdate.valueOf() >= bef1m ) : true );
        };
      break;
    default:
      condf = function(x) { return true; };
      break;
  }

  hasEnoughPubdate = function(job) {

    return (job.pubdate ? condf(job.pubdate) : true); // true in case of null.

  };

  upd();
}

/* called when any employtype is clicked */
function clkEmploytype(key){

  if (key < 0 || key > 2) return;

//  var condf;
  switch(key){
    case 0:
      condf = function(x) { return (x.search(/正社員/) != -1); };
      break;
    case 1:
      condf = function(x) { return (x.search(/契約社員/) != -1); };
      break;
    default:
      condf = function(x) { return true; };
      break;
  }

  // 比較用関数、条件、表示リスト → しぼりこみ
  hasEnoughEmploytype = (function(job) {
    return (job ? condf(job.employtype) : true); // true in case of null.
  });

  // 更新
  upd();
}

/* update job list, which ends up with 1st page. */
function upd(){
  list = new Array();
  for(var i = 0; i < jobs.length; i++) {
    if( hasEnoughSalary(jobs[i]) && hasEnoughEmploytype(jobs[i]) && hasEnoughPubdate(jobs[i]) ) {
      list.push(jobs[i]);
    }
  }
//  page = 1;
  show_page(1);
}

/* called when the "select-all" salary checkbox is clicked. */
function toggleSalary(cb){
  if(cb.checked) {
    $("div.qsalary input[@type=checkbox]").get(7).checked = false;
    $("div.qsalary input[@type=checkbox]").get(7).disabled = false;
  } else {
    var isChecked = false;
    $("div.qsalary input[@type=checkbox]").lt(7).each(function(){
      if (this.checked) isChecked = true;
    });
    if(!isChecked) {
      $("div.qsalary input[@type=checkbox]").get(7).checked = true;
      $("div.qsalary input[@type=checkbox]").get(7).disabled = true;
    }
  }
}

/* called when any salary checkbox is clicked. */
function clkSalary(cb, sw) {
  if (sw) { // 指定なし?
    if(cb.checked){
      $("div.qsalary input[@type=checkbox]").lt(7).each( function(){
	  this.checked = false;
      });
      cb.disabled = true;
    } else {
      // do nothing.
    }
  } else {
    toggleSalary(cb);
  }
  // 比較条件
  condfs = new Array();
  $("div.qsalary input[@type=checkbox]").each(function(i){
    if($(this).attr("checked")){
      switch(i){
        // ...
        case 0:
        condfs.push(getSalCompFunc(1000, null));
        break;
        case 1:
        condfs.push(getSalCompFunc(900, 1000));
        break;
        case 2:
        condfs.push(getSalCompFunc(800, 900));
        break;
        case 3:
        condfs.push(getSalCompFunc(700, 800));
        break;
        case 4:
        condfs.push(getSalCompFunc(600, 700));
        break;
        case 5:
        condfs.push(getSalCompFunc(500, 600));
        break;
        case 6:
        condfs.push(getSalCompFunc(400, 500));
        break;
        case 7: // なし
        condfs.push(getSalCompFunc(null, null));
        break;
      }
    }
  });

  hasEnoughSalary = function(x) {
    if(!x.salary) return false;
    if(x.salary.length < 1) return false;
    ms = x.salary.match(/[0-9]+[,0-9]*/g);
    var vals = new Array();
    if(ms && ms.length > 0) {
      for(var i = 0; i<ms.length; i++) {
        vals.push(ms[i].replace(",",""));
      }
    } else {
      vals.push(null);
    }
    res = false;
    for(var i=0; !res && i<vals.length; i++){
      for(var j=0; !res && j<condfs.length; j++){
        res = condfs[j](vals[i]);
      }
    }
    return res;
  };
  upd();
}

/* return the criteria with the passed lower limit and upper limit. */
function getSalCompFunc(low, up) {

  if(!low) {
    // low is null
    if(!up) {
      return (function(x){ return true; });
    } else {
      return (function(x){ return (x < up); });
    }
  } else {
    // low is not null
    if(!up) {
      return (function(x){ return (x >= low); });
    } else {
      return (function(x){ return (( x >= low) && ( x < up ));  });
    }
  }
}

/* enables all the ui objects. */
function activate_ui(sw){
    $("div.query input").attr("disabled", !sw);
}

/* show the job list just after the data is loaded. */
function load_data(){
  $.ajax({
    url: 'data.xml',
    type: 'GET',
    dataType: 'xml',
    timeout: 1000,
    error: function(){
      alert('Error loading XML document');
    },
    beforeSend: function(){
      $.blockUI.defaults.pageMessage = "データを読み込んでいます…";
      $.blockUI();
    },
    complete: function(){
      // 仕様上は $.unblockUI() だけでよいですが、なぜかIEでjavascriptエラーが生じるので fadeOut を挟んでいます
      $('.blockUI').fadeOut ('slow', function (){ $.unblockUI ()}); 
    },
    success: function(xml){
      //var jobs = new Array();
      $(xml).find('Row').each(function(i){
        if(i < 1){
          /* do nothing for it's header record. */
        } else if ( $('Data', $('Cell', $(this)).get(0) ).get(0) != null ) {
          var job = new Object();
          $('Cell', $(this)).each(function(j){
              // set properties from the loaded data.
	      var data = $('Data', $(this));
              switch(j){
              case 0:
		  job.id = data.output(); break;
              case 1:
		  job.title = data.output(); break;
 	      case 16:
		  job.salary =  data.output(); break;
	      case 12:
		  job.employtype =  data.output(); break;
 	      case 14:
 		  job.location =  data.output(); break;
 	      case 3:
		  job.pubdate =  data.output(); break;
	      }
	  });
          // add into the global lists.
          jobs.push(job);
          list.push(job);
	}
      });
      show_page(1);
    }
  });
}

function show_page(page){
  if(page < 0) return;

  $('table.joblist tbody').empty();
  if(list == null) {
    /* do nothing. */
  } else {
    var total = list.length;
    var end   = Math.min(page * ROWS, total);
    var start = (page - 1) * ROWS;
    for(var i = start, i_local = 1; i < end; i++, i_local++) {
	var str = '<tr>'
	    + '<input type="hidden" value="' + list[i].id + '" />'
	    + '<td rowspan="2">' + (i + 1) + '</td>'
	    + '<td class="top">' + list[i].pubdate + '</td>'
	    + '<td class="top">' + list[i].title.truncate() + '</td>'
	    + '<td class="top">' + list[i].location.truncate(15) + '</td>'
	    + '</tr><tr>'
	    + '<input type="hidden" value="' + list[i].id + '" />'
	    + '<td class="bottom">' + list[i].employtype + '</td>'
	    + '<td class="bottom" colspan="2">' + list[i].salary.truncate() + '</td></tr>'
	$('table.joblist tbody').append(str);
    }

    pages = Math.ceil(total / ROWS);
    // 検索結果件数、From 〜 To
    $('div#pageinfo p span.total').text('' + total );
    $('div#pageinfo p span.from').text('' + (start + 1));
    $('div#pageinfo p span.to').text('' + end);

    $('table.joblist tbody tr:even').hover(
      function(){
        $(this).addClass("hover");
	$(this).next().addClass("hover");
      },
      function(){
        $(this).removeClass("hover");
	$(this).next().removeClass("hover");
      }
    )

   // pagination の構築
    var ul = $('<ul></ul>');
    //前ページ
    if(page > 1){
        $('<li></li>').append(
          $('<a></a>').attr('href', 'javascript:void(0)').click(
    	funcfunc(page - 1)).text('<< 前')
        ).addClass('prevpage').appendTo(ul);
    }
    //リスト表示する最小ページ数
    var lb = page - Math.floor(PAGE_RANGES / 2);
    if (lb < 1) {
      lb = 1;
    }
    //リスト表示する最大ページ数
    var ub = Math.min( lb + PAGE_RANGES - 1, pages);
    var ub = lb + PAGE_RANGES - 1;
    //はみださないかチェック
    if (ub > pages) {
      lb = lb - (ub - pages);
      ub = pages;
      if(lb < 1) {
        lb = 1;
      }
    }
    //表示するページ数が決まったので、あとはhtml要素を生成
    if( lb > 1 ){
      var first_li = $('<li></li>').append(
        $('<a></a>').attr('href', 'javascript:void(0)').click(
    	funcfunc(1)).text('1'));
      if(lb > 2){
        first_li.append('&nbsp;…&nbsp;');
      }
      ul.append(first_li);
    }
    //PAGE_RANGES個分、リスト要素を生成
    for (var i=lb; i <= ub; i++){
        var li = $('<li></li>');
        if(i == page){
            li.addClass('currentpage').text('' + i);
        } else {
          li.append($('<a></a>').attr('href', 'javascript:void(0)')
            .click(funcfunc(i)).text('' + i));
        }
        ul.append(li);
    }
    //必要ならば最後のページのリストを生成
    if(ub < pages){
      var last_li = $('<li></li>').append(
        $('<a></a>').attr('href', 'javascript:void(0)').click(
        funcfunc(pages)).text('' + pages));
      if(ub < pages - 1){
        last_li.prepend('&nbsp;…&nbsp;');
      }
      ul.append(last_li);
    }
    // 次ページ
    if(page < pages){
        $('<li></li>').append(
          $('<a></a>').attr('href', 'javascript:void(0)').click(
    	    funcfunc(page + 1)).text('次 >>')).addClass('nextpage').appendTo(ul);
    }

    // pagination の表示
    var top = $('div#pagination').empty().append(ul);

    // ストライプを設定
    $('table.joblist tbody tr:odd').hover(
      function(){
        $(this).addClass("hover");
	$(this).prev().addClass("hover");
      },
      function(){
        $(this).removeClass("hover");
	$(this).prev().removeClass("hover");
      }
    );

    // hover効果を設定
    $('table.joblist tbody tr').each( function(i){
      $(this).click(function(){
        var id=$("input:hidden", $(this)).attr('value');
        $(location).attr("href", './detail.cgi?jid=' + id);
      });
      var idx = i % 4;
      if(idx == 2 || idx == 3) {
        $(this).addClass("even");
      }
    });

  }
}

/* 表示ページ数を内包した、表示＆スクロール関数のクロージャを生成 */
function funcfunc(_page) {

    return function(){
      show_page(_page);
      scroll("pageinfo");
    };

}