function WXForm() {
  this.Focus = function (id) {
    var obj = null;
    if (obj = document.getElementById(id + 'Title')) obj.className = 'cFormTitleSelected';
    if (obj = document.getElementById(id + 'Object')) obj.className = 'cFormObjectSelected';
    if (obj = document.getElementById(id + 'Help')) obj.className = 'cFormHelpSelected';
  }
  
  this.Blur = function (id) {
    var obj = null;
    if (obj = document.getElementById(id + 'Title')) obj.className = 'cFormTitle';
    if (obj = document.getElementById(id + 'Object')) obj.className = 'cFormObject';
    if (obj = document.getElementById(id + 'Help')) obj.className = 'cFormHelp';
  }
  
  this.SetFocus = function (form, tab, id) {
    var tNum = document.getElementById(form).getAttribute('wxTab');
    if (tNum == 1) try { document.getElementById(id).focus(); } catch (e) { }
    else {
      var tab = document.getElementById(id).getAttribute('wxTab');
      eval(document.getElementById(form).tabID.value + '.setSelectedIndex(' + tab + ');');
      try { document.getElementById(id).focus(); } catch (e) {}
    }
  }
  
  this.ShowSection = function (id, show) {
    var obj = document.getElementById(id);
    if (!obj) return;
    if (show == false) obj.style.display = 'none';
    else {
      try { obj.style.display = 'table'; } catch (e) { obj.style.display = 'inline'; }
    }
  }
  
  this.Check = function (form) {
    var error = new Array();
    var i     = 0;
    for (i=0; i<form.elements.length; i++) {
      var check = this.CheckElement(form, form.elements[i]);
      if (check != '') error[error.length] = check;
    }
    
    if (error.length == 0) return true;
    else {
      var message = '';
      message += '<div>' + 'متاسفانه بدلیل اشکالاتی در اطلاعات ثبت شده در فرم، امکان ارسال اطلاعات به سرور وجود ندارد. لطفا اشکالات مشخص شده را بررسی و رفع نموده و سپس مجددا جهت ثبت فرم اقدام نمایید.' + '</div><br>';
      for (i=0; i<error.length; i++) message += '&gt; ' + error[i] + '<br>';
      wxMessage.Show('اشکال در اطلاعات ثبت شده در فرم', message, true);
      return false;
    }
  }
  
  this.CheckElement = function (form, element) {
    try {
      var tab   = element.getAttribute('wxTab');
      var title = element.getAttribute('wxTitle');
      var error = element.getAttribute('wxError');
      
      try {
        var parent = element.parentNode;
        while (parent) {
          if ((parent.style.display == 'none') && (parent.className != 'tab-page')) return '';
          parent = parent.parentNode;
        }
      } catch (e) {}
  
      if ((error == '') || (error == null)) return '';
      error = eval('new Array(' + error + ')');
      
      var i = 0;
      for (i=0; i<error.length; i++) {
        var span = '<span class="cLink" onClick="wxMessage.Hide(); wxForm.SetFocus(\'' + form.getAttributeNode('id').value + '\', ' + (tab + 1) + ', \'' + element.id + '\');">';
        
        if ((error[i] == 'empty') && (element.value == '')) return span + title + ' مشخص نشده است.' + '</span>';
        if ((error[i] == 'email') && (element.value != '') && (!this.CheckEmail(element.value))) return span + title + ' صحیح مشخص نشده است.' + '</span>';
        if (error[i].substr(0, 7) == 'length,') {
          var size = error[i].substr(7).split('-');
          if (size.length == 2) {
            if ((element.value.length < size[0]) || (element.value.length > size[1])) return span + 'طول ' + title + ' باید بین ' + wx.PNumber(size[0]) + ' تا ' + wx.PNumber(size[1]) + ' کاراکتر باشد.' + '</span>';
          } else {
            if (element.value.length < size[0]) return span + 'طول ' + title + ' باید حداقل ' + wx.PNumber(size[0]) + ' کاراکتر باشد.' + '</span>';
          }
        }
        if (error[i].substr(0, 5) == 'char,') {
          var chars = error[i].substr(5), c = 0;
          var valid = '';
          for (c=0; c<chars.length; c++) {
            switch (chars.substr(c, 1)) {
              case '0': valid += '0123456789'; break;
              case 'a': valid += 'abcdefghijklmnopqrstuvwxyz'; break;
              case 'A': valid += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; break;
              case '-': valid += '-'; break;
            }
          }
          if (!this.CheckChar(element.value, valid)) return span + 'از کاراکتر های مجاز در ' + title + ' استفاده نشده است.' + '</span>';
        }
        if ((error[i] == 'integer') && (!this.CheckChar(element.value, '0123456789'))) return span + 'مقدار ' + title + ' باید به صورت عدد صحیح مشخص شود.' + '</span>';
        if (error[i].substr(0, 8) == 'between,') {
          var value = error[i].substr(8).split('-');
          if ((parseInt(element.value) < parseInt(value[0])) || (parseInt(element.value) > parseInt(value[1])))
            return span + 'مقدار ' + title + ' باید بین ' + wx.PNumber(value[0]) + ' و ' + wx.PNumber(value[1]) + ' انتخاب شود.';
        }
      }
    } catch (e) { return ''; }
    return '';
  }

  this.CheckEmail = function (email) {
    var splitted = email.match("^(.+)@(.+)$"); 
    if(splitted == null) return false; 
    if(splitted[1] != null ) { 
      var regexp_user=/^\"?[\w-_\.]*\"?$/; 
      if(splitted[1].match(regexp_user) == null) return false; 
    } 
  
    if(splitted[2] != null) { 
      var regexp_domain=/^[\w-\.]*\.[A-Za-z]{2,4}$/; 
      if(splitted[2].match(regexp_domain) == null) { 
        var regexp_ip =/^\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\]$/; 
        if(splitted[2].match(regexp_ip) == null) return false; 
      }
      return true; 
    } 
    return false; 
  }
  
  this.CheckChar = function (value, check) {
    if (!value) return true;
  
    var i = 0;
    for (i=0; i<value.length; i++) {
      if (check.indexOf(value.charAt(i)) == -1) return false;
    }
    return true;
  }
  
  this.SelectImage = function (id) {
    var obj  = document.getElementById(id);
    var dir  = document.getElementById(id + 'Dir').value;
    var page = document.getElementById(id + 'Page').value;
    
    wxMessage.Show('لیست تصاویر', wxMessage.Progress('دریافت لیست تصاویر'), true);
    wxQuery.Reset('/admin/ajax/image/list/');
    wxQuery.AddData('id', id);
    wxQuery.AddData('dir', dir);
    wxQuery.AddData('page', page);
    wxAjax.AddQuery(wxQuery);
  }

  this.UploadImage = function (id, action) {
    if (!action) {
      var obj  = document.getElementById(id);
      var dir  = document.getElementById(id + 'Dir').value;
    
      wxMessage.Show('آپلود تصویر', wxMessage.Progress('دریافت فرم آپلود'), true);
      wxQuery.Reset('/admin/ajax/image/upload/');
      wxQuery.AddData('id', id);
      wxQuery.AddData('dir', dir);
      wxAjax.AddQuery(wxQuery);
    } else {
      var obj = document.getElementById(id + 'Upload');
      if (obj.value == '') { obj.focus(); return; }
     
      wxPost.Reset('/admin/ajax/image/upload/');
      wxPost.SetTarget(id + 'Frame');
      wxPost.AddObject('id', id);
      wxPost.AddObject('dir', document.getElementById(id + 'Path').value);
      wxPost.AddObject('rewrite', ((document.getElementById(id + 'Overwrite').checked) ? 'on' : ''));
      wxPost.AddFile(id + 'Upload');
      wxPost.Post();
      
      document.getElementById(id + 'Message').innerHTML = wxMessage.Progress('ارسال مشخصات آپلود');
    }
  }
  
  this.SelectMember = function (id) {
    var obj  = document.getElementById(id);
    var chr  = document.getElementById(id + 'Char').value;
    var page = document.getElementById(id + 'Page').value;
    
    wxMessage.Show('لیست اعضا', wxMessage.Progress('دریافت لیست اعضا'), true);
    wxQuery.Reset('/admin/ajax/member/list/');
    wxQuery.AddData('id', id);
    wxQuery.AddData('char', chr);
    wxQuery.AddData('page', page);
    wxAjax.AddQuery(wxQuery);
  }
  
  this.SelectDate = function (id) {
    var obj   = document.getElementById(id);
    var value = ((obj.value == '') ? '1350-01-01' : obj.value);
    
    var year  = value.substr(0, 4);
    var month = value.substr(5, 2); if (month.substr(0, 1) == '0') month = month.substr(1);
    var day   = value.substr(8, 2); if (day.substr(0, 1) == '0') day = day.substr(1);
    wxCalendar.Show(id, [year, month, day], 'تغییر تاریخ');
  }
  
  this.GetRelatedNumber = function (id, module) {
    var number = 0;
    var rData  = eval(id + 'Data');
    for (i=0; i<rData.length; i++) {
      if (rData[i][0] == module) number++;
    }
    return number;
  }
  
  this.GetRelatedTitle = function (id, module) {
    var title = '';
    title += wx.GetData('RelatedTitle_' + module);
    title += ' - حداکثر: ' + wx.PNumber(wx.GetData('RelatedMax_' + module));
    title += ' - ثبت شده: ' + wx.PNumber(this.GetRelatedNumber(id, module));
    return title;
  }
  
  this.GetRelated = function (id, module, page) {
    if (wx.GetData('RelatedMax_' + module) <= this.GetRelatedNumber(id, module)) {
      wxMessage.Show(this.GetRelatedTitle(id, module), '<br><br><center>' + 'حداکثر تعداد ' + wx.GetData('RelatedTitle_' + module) + ' به عنوان' + '<br>' + 'اطلاعات مرتبط انتخاب شده است.' + '</center><br><br>', true);
      return;
    }
    
    wxMessage.Show(this.GetRelatedTitle(id, module), wxMessage.Progress('دریافت لیست اطلاعات از سرور'), true);
    wxQuery.Reset('/admin/' + module + '/related/');
    wxQuery.AddData('id', id);
    wxQuery.AddData('page', page);
    wxAjax.AddQuery(wxQuery);
  }
  
  this.CheckRelated = function (related, data) {
    var i = 0;
    for (i=0; i<related.length; i++) {
      if ((related[i][0] == data[0]) && (related[i][1] == data[1])) return true;
    }
    return false;
  }
  
  this.SortRelated = function (a, b) {
    if (a[0] == b[0]) return 0;
    else if (a[0] > b[0]) return 1;
    else return -1;
  }
  
  this.AddRelated = function (id, module, data, title) {
    var rData = eval(id + 'Data');
    if (this.CheckRelated(rData, [module, data])) return;
    rData[rData.length] = [module, data, title, wx.GetData('RelatedTitle_' + module)];
    wxMessage.SetTitle(this.GetRelatedTitle(id, module), true);
    this.SetRelated(id);
    this.ShowRelated(id);
    
    if (wx.GetData('RelatedMax_' + module) <= this.GetRelatedNumber(id, module)) {
      wxMessage.Change('<br><br><center>' + 'حداکثر تعداد ' + wx.GetData('RelatedTitle_' + module) + ' به عنوان' + '<br>' + 'اطلاعات مرتبط انتخاب شده است.' + '</center><br><br>');
    }
  }

  this.DeleteRelated = function (id, module, data) {
    var rData = eval(id + 'Data'); var i = 0;
    for (i=0; i<rData.length; i++) {
      if ((rData[i][0] == module) && (rData[i][1] == data)) {
        rData.splice(i, 1);
        this.SetRelated(id);
        this.ShowRelated(id);
        return;
      }
    }    
  }
  
  this.SetRelated = function (id) {
    var rData = eval(id + 'Data');
    var i = 0, value = [];
    for (i=0; i<rData.length; i++) {
      value[value.length] = rData[i][0] + ':' + rData[i][1];
    }
    document.getElementById(id).value = value.join('|');
  }
  
  this.ShowRelated = function (id) {
    var rData = eval(id + 'Data');
    var message = '';
    if (rData.length == 0) message = '<br>' + 'اطلاعات مرتبط انتخاب نشده است.' + '<br>';
    else {
      rData = rData.sort(wxForm.SortRelated);
      var type = '', i = 0;;
      message  = '';
      message += '<table cellpadding="2" cellspacing="2" width="100%" border="0">';
      for (i=0; i<rData.length; i++) {
        if (type != rData[i][3]) {
          if (type != '') message += '<tr><td colspan="2">' + '&nbsp;' + '</td></tr>';
          message += '<tr><td colspan="2" class=\"cRelatedTitle\">' + rData[i][3] + '</td></tr>';
          type = rData[i][3];
        }
        message += '<tr>';
        message += '<td width="90%" class="cRelatedLine' + (i % 2) + '">' + rData[i][2] + '</td>';
        message += '<td width="10%" class="cRelatedLine' + (i % 2) + '" align="center">' + '<span class="cLink" onClick="wxForm.DeleteRelated(\'' + id + '\', \'' + rData[i][0] + '\', \'' + rData[i][1] + '\');">' + '[حذف]' + '</span>' + '</td>';
        message += '</tr>';
      }
      message += '</table>';
    }
    document.getElementById(id + 'Content').innerHTML = message;
  }
  
  this.ShowWriter = function (id, writer) {
    document.getElementById(id).value = writer.join('|');
    var list = document.getElementById(id + 'List');
    var i    = 0;
    
    while (list.options.length != 0) list.remove(0);
    for (i=0; i<writer.length; i++) {
      list.options[list.options.length] = new Option(writer[i], writer[i]);
    }
    list.focus();
  }
  
  this.AddWriter = function (id, username) {
    if (username == '') {
      wxMessage.Show('ثبت نویسنده جدید', wxMessage.Progress('دریافت لیست نویسندگان از سرور'), true);
      wxQuery.Reset('/admin/ajax/writer/');
      wxQuery.AddData('id', id);
      wxAjax.AddQuery(wxQuery);
    } else {
      var value = document.getElementById(id).value;
      if (value == '') { value = [] } else { value = value.split('|'); }
      var i     = 0;
      for (i=0; i<value.length; i++) {
        if (value[i] == username) return;
      }
      
      value[value.length] = username;
      wxForm.ShowWriter(id, value);
    }
  }
  
  this.DeleteWriter = function (id) {
    var list = document.getElementById(id + 'List');
    if (list.selectedIndex == -1) return;
    
    var  i = 0, value = [];
    for (i=0; i<list.options.length; i++) {
      var option = list.options[i].value;
      if (option != list.value) value[value.length] = option;
    }
    wxForm.ShowWriter(id, value);
  }
  
  this.UpWriter = function (id) {
    var list = document.getElementById(id + 'List');
    if (list.selectedIndex == -1) return;
    
    var  i = 0, index = 0, value = [];
    for (i=0; i<list.options.length; i++) {
      var option = list.options[i].value;
      if (option == list.value) index = i;
      value[value.length] = option;
    }
    
    if (index == 0) return "";
    var temp = value[index];
    value[index] = value[index - 1];
    value[index - 1] = temp;
    wxForm.ShowWriter(id, value);
  }
  
  this.DownWriter = function (id) {
    var list = document.getElementById(id + 'List');
    if (list.selectedIndex == -1) return;
    
    var  i = 0, index = 0, value = [];
    for (i=0; i<list.options.length; i++) {
      var option = list.options[i].value;
      if (option == list.value) index = i;
      value[value.length] = option;
    }
    
    if (index >= (list.options.length - 1)) return "";
    var temp = value[index];
    value[index] = value[index + 1];
    value[index + 1] = temp;
    wxForm.ShowWriter(id, value);
  }
  
  this.ShowAttachment = function (id, writer) {
    document.getElementById(id).value = writer.join('\n');
    var list = document.getElementById(id + 'List');
    var i    = 0;
    
    while (list.options.length != 0) list.remove(0);
    for (i=0; i<writer.length; i++) {
      list.options[list.options.length] = new Option(writer[i], writer[i]);
    }
    list.focus();
  }
  
  this.SelectAttachment = function (id) {
    wxMessage.Show('انتخاب فایل ضمیمه', wxMessage.Progress('دریافت لیست فایل ها از سرور'), true);
    wxQuery.Reset('/admin/ajax/attachment/select/');
    wxQuery.AddData('id', id);
    wxQuery.AddData('dir', document.getElementById(id + 'Dir').value);
    wxQuery.AddData('page', document.getElementById(id + 'Page').value);
    wxAjax.AddQuery(wxQuery);
  }
  
  this.AddAttachment = function (id, file) {
    var value = document.getElementById(id).value;
    if (value == '') { value = [] } else { value = value.split('\n'); }
    var i     = 0;
    for (i=0; i<value.length; i++) {
      if (value[i] == file) return;
    }
      
    value[value.length] = file;
    wxForm.ShowAttachment(id, value);
  }
  
  this.DeleteAttachment = function (id) {
    var list = document.getElementById(id + 'List');
    if (list.selectedIndex == -1) return;
    
    var  i = 0, value = [];
    for (i=0; i<list.options.length; i++) {
      var option = list.options[i].value;
      if (option != list.value) value[value.length] = option;
    }
    wxForm.ShowAttachment(id, value);
  }
  
  this.SetColor = function(id, value) {
    var obj = document.getElementById(id + 'Preview');
    if (value == '') obj.style.borderTop = '0px'; 
    else  obj.style.borderTop = '7px solid ' + value;
  }
  
  this.SelectColor = function (id) {
    wxMessage.Show('انتخاب رنگ', wxMessage.Progress('دریافت اطلاعات از سرور'), true);
    wxQuery.Reset('/admin/ajax/color/');
    wxQuery.AddData('id', id);
    wxAjax.AddQuery(wxQuery);
  }
  
  this.NumberValue = function (value, title) {
    if (value == '') return 'مقدار مشخص نشده است.';
    if (!this.CheckChar(value, '0123456789')) return 'مقدار صحیح مشخص نشده است.';
    
    var N1000 = new Array('', ' هزار', ' میلیون', ' میلیارد', ' هزار میلیارد');
    var N100  = new Array('صد', 'دویست', 'سیصد', 'چهارصد', 'پانصد', 'ششصد', 'هفتصد', 'هشتصد', 'نهصد');
    var N10   = new Array('ده', 'بیست', 'سی', 'چهل', 'پنجاه', 'شصت', 'هفتاد', 'هشتاد', 'نود');
    var N1    = new Array('یک', 'دو', 'سه', 'چهار', 'پنج', 'شش', 'هفت', 'هشت', 'نه', 'ده', 'یازده', 'دوازده', 'سیزده', 'چهارده', 'پانزده', 'شانزده', 'هفده', 'هجده', 'نوزده', 'بیست');
  
    value = parseInt(value);
    if (value == 0) return 'صفر' + ' ' + title;
  
    var parts = new Array();
    while (value >= 1000) {
      parts[parts.length] = (value % 1000);
      value = (value - (value % 1000)) / 1000;
    }
    if (value > 0) parts[parts.length] = value;
  
    var i = 0; var ret = '';
    for (i=0; i<parts.length; i++) {
      var val = ''; var num = parts[i];
    
      if (num >= 100) {
        val += N100[(parseInt(num / 100) - 1)];
        num -= parseInt(num / 100) * 100;
      
        if (num > 0) val += ' و ';
      }
    
      if (num != 0) {
        if (num > 20) {
          val += N10[(parseInt(num / 10) - 1)];
          num -= parseInt(num / 10) * 10;
      
          if (num > 0) val += ' و ' + N1[num - 1];
        } else {
          val += N1[num - 1];
        }
      }
    
      if (val != '') {
        if (ret != '') ret = ' و ' + ret;
        ret = val + N1000[i] + ret;
      }
    }
    return ret + ' ' + title;
  }
}