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;
    var hp = this.getMainBox().find('#hpKey_'+id);
    if(hp.length < 1){
      return false;
    }
    var hpA = $('img:eq(1)', hp);
    var hpB = $('img:eq(2)', hp);
    var redHP    = 0.33; // меньше 30% красный цвет
    var yellowHP = 0.66; // меньше 60% желтый цвет, иначе зеленый
    if(curHP > maxHP){
        curHP = maxHP;
    }
    var text = curHP + '/' + maxHP;
    var lengthHP = 170 - (text.length - 1) * 8;
    var sizeFirst  = Math.round((lengthHP / maxHP) * curHP);
    var 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);
  var m = $('<div class="sd-container"></div>').css('width',options.width);
  var t = $('<div class="sd-title">').text(options.title);
  var c = $('<img class="sd-closer" src="/i/clear.gif" title="Закрыть окно" alt="X">')
            .click(function(){return options.onClose.call($(this).closest('div.sd-container'))});
  var 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(var 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){
  var tmp = this._sd(options);
  return this.getMainBox().append(tmp);
}

H.prototype.sdOneInput = function(options){
  var onSubmit2 = options.onSubmit;
  options = $.extend({},this.sdOptionsDefault, {inputName: 'target', inputValue: '', grabber: null}, options);
  var 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(){
    var 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';
    }
    var 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){
  var obj = this;
  this.clear();
  var 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));
  }
}