function H(isOutBox){
  this.document = document;
  this.isOutBox = isOutBox;
  this.iframe = this.isOutBox ? $('#mainbox') : $('body');  
  
  // DOM-элемент, который перехватывает клик по логину
  //this.grabLogin = null;
  // DOM-элемент, который перехватывает клик по названию шмотки
  //this.grabItem = null;
  this.grabLogin = new Grabber({inputClass: 'grabLogin'});
  this.grabItem = new Grabber({inputClass: 'grabLogin'});
  // storage
  this.data = {};
}

H.prototype.toString = function(){
  return 'This is H-object';
}

H.prototype.getMainBox = function(){
  return this.isOutBox ? this.iframe.contents().find('body') : $('body');
}

H.prototype.loadMainBox = function(location){
  location = location || '/main.php';
  this.iframe.attr('src',location);
}

H.prototype.loadDocument = function(location){
  this.document.location = location;
}

// ======== storage

H.prototype.set = function(key, value){
  this.data[key] = value;
}

H.prototype.get = function(key, defaultValue){
  return undefined == this.data[key] ? defaultValue : this.data[key];
}

H.prototype.setHP = function(id, curHP, maxHP){
    curHP = curHP || 0;
    maxHP = maxHP || 0;
    const hp = this.getMainBox().find('#hpKey_' + id);
    if(hp.length < 1){
      return false;
    }
    const hpA = $('img:eq(1)', hp);
    const hpB = $('img:eq(2)', hp);
    const redHP = 0.33; // меньше 30% красный цвет
    const yellowHP = 0.66; // меньше 60% желтый цвет, иначе зеленый
    if(curHP > maxHP){
        curHP = maxHP;
    }
    const text = curHP + '/' + maxHP;
    const lengthHP = 170 - (text.length - 1) * 8;
    const sizeFirst = Math.round((lengthHP / maxHP) * curHP);
    const sizeSecond = lengthHP - sizeFirst;
    hpA.attr('width', sizeFirst);
    hpB.attr('width', sizeSecond);
    if(curHP / maxHP < redHP){
        hpA.attr('src', '/i/1red.gif');
    }else{
        if(curHP / maxHP < yellowHP){
            hpA.attr('src', '/i/1yellow.gif');
        }else{
            hpA.attr('src', '/i/1green.gif');
        }
    }
    hp.html(hp.html().substring(0, hp.html().lastIndexOf(':') + 1) + Math.round(curHP) + "/" + maxHP);
}

/* ------------------ перехват клика по логину юзера -------------------------------------------- * /
H.prototype.setGrabLogin = function(input){
  var obj = this;
  this.clearGrabLogin();
  var tmp = $(input);
  if(tmp.length > 0){
    this.grabLogin = tmp.get(0);
    $(this.grabLogin)
       .addClass('grabLogin')
       .dblclick(function(){obj.toggleGrabLogin(this)})
       .select();
    return true;
  }
  return false;
}

H.prototype.clearGrabLogin = function(){
  $(this.grabLogin).removeClass('grabLogin');
  this.grabLogin = null;
},

H.prototype.toggleGrabLogin = function(input){
  if($(input).hasClass('grabLogin')){
    this.clearGrabLogin();
  }else{
    this.setGrabLogin($(input));
  }
}
/* -------------------------------- простые диалоги --------------------------------------------- */

H.prototype.sdOptionsDefault = {
  formMethod: 'POST',
  formAction: '',
  formClass:  '',
  title:    'заголовок не указан',
  width:    250,
  data:     {},
  content:  '<span>контент не указан</span>',
  onSubmit: function(){return true;},
  onClose:  function(){this.remove()}
}

H.prototype._sd = function(options){
  options = $.extend({}, this.sdOptionsDefault, options);
    const m = $('<div class="sd-container"></div>').css('width', options.width);
    const t = $('<div class="sd-title">').text(options.title);
    const c = $('<img class="sd-closer" src="/i/clear.gif" title="Закрыть окно" alt="X">')
        .click(function () {
            return options.onClose.call($(this).closest('div.sd-container'))
        });
    const f = $('<form class="sd-form"></form>')
        .attr('method', options.formMethod)
        .attr('action', options.formAction)
        .submit(function () {
            return options.onSubmit.call($(this).closest('div.sd-container'))
        });
    for(let i in options.data){
    $('<input type=hidden>').attr('name',i).val(options.data[i]).appendTo(f);
  }
  if(options.formClass){
    f.addClass(options.formClass);
  }
  $('div.sd-container', this.getMainBox()).remove();
  return m.append(t.prepend(c)).append(f.append(options.content));
}

H.prototype.sd = function(options){
    const tmp = this._sd(options);
    return this.getMainBox().append(tmp);
}

H.prototype.sdOneInput = function(options){
    let onSubmit2 = options.onSubmit;
    options = $.extend({},this.sdOptionsDefault, {inputName: 'target', inputValue: '', grabber: null}, options);
    const i = $('<input type="text" class="text">')
        .css({'width': options.width - 45})
        .attr('name', options.inputName)
        .val(options.inputValue);
    if(options.grabber &&  this[options.grabber] instanceof Grabber){
    this[options.grabber].set(i);
  }else{
    i.select();
  }
  options.content.append($('<div></div>')
                          .append(i)
                          .append('<input type="submit" class="button" style="width:33px;" value=" »» ">'));
  options.onSubmit = function(){
      const v = i.val($.trim(i.val())).val();
      if(v.length <= 0){
      alert('Не заполнено обязательное поле');
      return false
    }
    if(typeof onSubmit2 == 'function'){
      return onSubmit2.call(this);
    }
    return true;
  }
  return this.sd(options);
}

H.prototype.sdLogin = function(options){
  options.content = $('<div>Укажите логин персонажа:<br><small>(можно кликнуть по логину в чате)</small></div>');
  options.grabber = 'grabLogin';
  return this.sdOneInput(options);
}

H.prototype.sdItem = function(options){
  options.content = $('<div>Укажите название или s/n предмета:<br><small>(можно кликнуть по названию в рюкзаке)</small></div>');
  options.grabber = 'grabItem';
  options.width   = 270;
  return this.sdOneInput(options);
}
/**
* Функция для обратной совместимости
*  Не надо её использовать в новом коде!
*/
H.prototype.sdFindLogin = function(title, formAction, inputName, inputValue){
  return this.sdLogin({
    title:      title,
    formAction: formAction,
    inputName:  inputName,
    inputValue: inputValue});
}

/**
* Функция для обратной совместимости
*  Не надо её использовать в новом коде!
*/
H.prototype.sdFindItem = function(title, formAction, inputName, inputValue){
  return this.sdItem({
    title:      title,
    formAction: formAction,
    inputName:  inputName,
    inputValue: inputValue});
}
/* ----------------------- вывод системных сообщений -------------------------------------------- */

H.prototype._popupConfig = {
      'd':[10000, 'Отладочное сообщение'],
      'i':[3000 , 'Сообщение'],
      'w':[5000 , 'Предупреждение'],
      'e':[0    , 'Ошибка']
     }
     
H.prototype.msgPopup = function(type, text){
    if(this._popupConfig[type] == undefined){
      type = 'w';
    }
    const conf = this._popupConfig[type];
    $.jGrowl(text,{
             header: '<img src="/i/jgrowl_moover.png" alt="<>" class="jgrowl-moover" title="Передвинуть"> ' + conf[1],
             glue:   'before',
             life:   conf[0],
             sticky: conf[0] <= 0,
             theme:  'msg_' + type
         });
}


/* ================== перехват клика на логине/шмотке и т.п. ==================================== */

function Grabber(options){
  this.options = $.extend({}, this.optionsDef, options);
  this.input = null;

}
Grabber.prototype.toString = function(){
  return 'This is Grabber-object';
}

Grabber.prototype.optionsDef = {
  inputClass: 'grab'
}

Grabber.prototype.get = function(){
  return this.input;
}

Grabber.prototype.isActive = function(){
  return $(this.input).is(':visible');
}

Grabber.prototype.set = function(input){
    const obj = this;
    this.clear();
    const tmp = $(input);
    if(tmp.length > 0){
    this.input = tmp.get(0);
    $(this.input)
       .addClass(this.options.inputClass)
       .dblclick(function(){obj.toggle(this)})
       .select();
    return true;
  }
  return false;
}

Grabber.prototype.clear = function(){
  $(this.input).removeClass(this.options.inputClass);
  this.input = null;
},

Grabber.prototype.toggle = function(input){
  if($(input).hasClass(this.options.inputClass)){
    this.clear();
  }else{
    this.set($(input));
  }
}