// Ajax Control Class
function Ajax(options) {
  // 클래스 시작 확인
  // console.log('start new ajax');

  // 필수옵션 체크
  if (options === undefined || options.url === undefined) {
    alert('ajax 호출을 처리할 url을 입력해 주세요.');
    return false;
  }

  // 변수 설정
  var xhttp = new XMLHttpRequest();
  var settings = {};                       // setting 정보
  var queryData = '';                      // get 방식으로 전달할 데이타
  var formData = new FormData();           // post 방식으로 전달할 데이타
  var dataText = '';                       // ajax call에서 받은 정보 (text 원본)
  var data = {};                           // ajax call에서 받은 정보 (JSON -> 객체)
  var controlData = new ControlData();

  // 옵션체크
  settings.url = options.url;
  settings.method = (options === undefined || options.method === undefined) ? 'post' : options.method;
  settings.sendData = (options === undefined || options.sendData === undefined) ? {} : options.sendData;
  settings.formName = (options === undefined || options.formName === undefined) ? '' : options.formName;
  settings.moveUrl = (options === undefined || options.moveUrl === undefined) ? '' : options.moveUrl;
  settings.confirmMsg = (options === undefined || options.confirmMsg === undefined) ? '' : options.confirmMsg;   // 전송전에 confirm 문의
  settings.mode = (options === undefined || options.mode === undefined) ? '' : options.mode;
  settings.beforeSend = (options === undefined || options.beforeSend === undefined) ? function() {} : options.beforeSend;
  settings.success = (options === undefined || options.success === undefined) ? function() {} : options.success;
  settings.fail = (options === undefined || options.fail === undefined) ? function() {} : options.fail;
  settings.complete = (options === undefined || options.complete === undefined) ? function() {} : options.complete;


  // ajax 결과 처리
  xhttp.onreadystatechange = function() {
    // console.log('readyState : ' + this.readyState  + ' / status : ' + this.status + ' / responseText : ' + this.responseText);
    // xhttp.abort();  // send() 이후에 효과
    if (this.readyState === 4) {
      if (this.status === 200) {
        dataText = this.responseText;
        try {
          data = JSON.parse(dataText);
          // console.log(dataText);
          // console.log(data);
          success(data);
        } catch(e) {
          fail('data');
          console.error(e);
          console.warn(this.responseText);
        }
      } else {  // 404, 500 에러 발생시
        fail('status');
        console.warn(this.responseText);
      }
      complete();
    }
  }
  // load 이벤트는 미사용
  // xhttp.onload = function() {console.log('load');}


  // Ajax Call 전송
  function send() {
    // confirm 기능 확인
    if (settings.confirmMsg !== '') {
      if (confirm(settings.confirmMsg) === false) return false;
    }

    // 전송전에 처리할 기능
    beforeSend();

    // 전송
    if (settings.method === 'get') {
      // GET 으로 전달할 데이터 정리
      queryData = controlData.getQueryData(settings.sendData);
      xhttp.open(settings.method, settings.url + queryData, true);
      xhttp.send();
    } else if (settings.method === 'post') {
      formData = controlData.getFormData(settings.formName, settings.sendData);
      xhttp.open(settings.method, settings.url, true);
      xhttp.send(formData);
    }
  }

  // 오류정보에 대한 처리
  function checkValidation(message, formName, index) {   // 대상 폼 + 순서(index = 0, 1, 2, ...)
    alert(message);

    var index = (index === undefined) ? 0 : index;
    var element = document.querySelectorAll('[name="' + formName + '"]')[index];
    if (element === undefined || element.length === 0) return false;

    var tagName = element.tagName.toLocaleLowerCase();
    var type = element.type.toLocaleLowerCase();
    element.focus();
  }


  function beforeSend() {
    console.log('[before send]');
    settings.beforeSend();
  }


  function success(data) {
    console.log('[success]');
    // console.log(dataText);
    console.log(data);

    // mode별 동작 설정
    if (settings.mode === 'set') {
      if (data.status === 'fail') {
        if (data.index === undefined) data.index = 0;
        checkValidation(data.message, data.name, data.index);
      } else if (data.status === 'success') {
        alert(data.message);
        // 이동여부 확인
        if (settings.moveUrl !== '') {
          (settings.moveUrl === 'reload') ? location.reload() : location.href = settings.moveUrl;
        }
      }
    } else if (settings.mode === 'get') {
      if (data.status === 'fail') {
        if (data.index === undefined) data.index = 0;
        checkValidation(data.message, data.name, data.index);
      } else if (data.status === 'success') {
        // setDataToForm(data);
      }
    }

    // 외부 추가 기능 처리
    settings.success();
  }


  function fail(type) {
    console.log('[fail]');
    if (type === 'data') {
      alert('Ajax 전송결과 처리 중 오류가 발생했습니다.');
    } else if (type === 'status') {
      alert('대상 파일에 정상적으로 접근할 수 없습니다.');
    }
    settings.fail();
  }


  function complete() {
    console.log('[complete]');
    settings.complete();
  }


  // 외부 연계용 메소드
  this.getData = function() {return data;}
  this.send = function() {send();}
}




// Data 처리 Class
function ControlData() {

  // data를 query string으로 변환
  function getQueryData(data) {
    var queryString = '';
    for (var x in data) {
      queryString += (queryString === '') ? '?' : '&';
      queryString += x + '=' + data[x];
    }

    return queryString;
  }

  // 데이터를 FormData에 반영
  function getFormData(formName, customData) {
    // 유효성 검사
    if (formName === undefined) {
      alert('데이터를 처리할 From 요소의 name이 지정되지 않았습니다.');
      return false;
    }

    var formData = new FormData();
    var customData = (customData === undefined) ? {} : customData;

    // customData 에 전달된 정보
    for (var x in customData) {
      formData.append(x, customData[x]);
    }

    // 대상 Form에 포함된 정보
    var form = document.querySelector('[name="' + formName + '"]');
    if (!form) return formData;   // 대상 폼이 없는 경우 현재까지의 정보만 전달
    var elements = form.querySelectorAll('[name]');
    for (var i = 0; i < elements.length; i++) {
      var tagName = elements[i].tagName.toLocaleLowerCase();
      var type = (tagName === 'input') ? elements[i].type.toLocaleLowerCase() : '';
      var value = '';
      // checkbox, radio
      if (tagName === 'input' && (type === 'checkbox' || type === 'radio')) {
        value = elements[i].value.trim();
        if (elements[i].checked) formData.append(elements[i].name, value);
      } else if (tagName === 'input' && type === 'file') {  // 첨부파일
        for (var j = 0; j < elements[i].files.length; j++) {
          formData.append(elements[i].name, elements[i].files[j]);
        }
      } else {  // input(text 형태) / select / textarea
        value = elements[i].value.trim();
        formData.append(elements[i].name, value);
        // console.log(elements[i].name + ' : ' + elements[i].value.trim());
      }
    }

    return formData;
  }


  // 전달된 데이터를 form에 반영
  function setDataToForm(data) {  // data['html'] / data['real']로 구성되어야 함 (중요!!)
    var html = data['html'];
    var real = data['real'];

    var elements = document.querySelectorAll('input[name], select[name], textarea[name], div[data-name]');
    for (var i = 0; i < elements.length; i++) {
      var tagName = elements[i].tagName.toLocaleLowerCase();
      var type = (elements[i].type) ? elements[i].type.toLocaleLowerCase() : '';
      var name = '';
      if (tagName === 'div') {
        name = (elements[i].getAttribute('data-name')) ? elements[i].getAttribute('data-name').replace('[]', '') : '';
      } else {
        name = (elements[i].name) ? elements[i].name.replace('[]', '') : '';
      }

      // 값 입력
      if (Array.isArray(real[name]) === true) {
        for (var j = 0; j < real[name].length; j++) {
          var el = document.querySelectorAll('[name="' + name + '[]"]');
          for (var k = 0; k < el.length; k++) {
            if (el[k] === elements[i]) {
              if (tagName === 'div') {
                elements[i].innerHTML = real[name][k];
              } else {
                elements[i].value = real[name][k];
              }
            }
          }
        }
      } else {
        if (tagName === 'div') {
          elements[i].innerHTML = real[name];
        } else {
          elements[i].value = real[name];
        }
      }
    }
  }

  // 외부용 함수
  this.getQueryData = function (data) {return getQueryData(data);}
  this.getFormData = function (formName, customData) {return getFormData(formName, customData);}
  this.setDataToForm = function (data) {setDataToForm(data);}
}







