
  var multiBlocks = new Array();
  var conditionalValidators = ['RequiredAny', 'RequiredBoth', 'RequiredIf'];
  
  /**
   * Insert a new block into multiBlock Elements
   * @param string blockId
   */
  function addMultiBlock(blockId) {
	var addButtonDd = $(blockId);
	var rowNumber = multiBlocks[blockId]['rowNumber'];
	var isFirstElement = true;
	
	// remove button
	var ddEl = new Element('dd', {
	  'id': blockId + '_' + rowNumber + '-remove',
	  'class': 'mb_remove'
	});
	var buttonEl = new Element('button', {
  	  'type': 'button',
  	  'events': {
  	    'click': function() {
            removeMultiBlock(blockId, rowNumber)
  	    }
  	  },
  	  'text': multiBlocks[blockId]['removeButton']
    });
	buttonEl.inject(ddEl);
	ddEl.inject(addButtonDd, 'before');
	
	for (elementId in multiBlocks[blockId]['elements']) {
      var element = multiBlocks[blockId]['elements'][elementId];
      
      // label
      var dtEl = new Element('dt', {
        'id': blockId + '_' + rowNumber + '_' + elementId + '-label',
        'class': 'mb_row'
      });
      var labelEl = new Element('label', {
        'for': blockId + '_' + rowNumber + '_' + elementId,
        'class': element['options']['class'],
        'text': element['options']['label']
      });
      if (element['options']['class'].contains('conditional')) {
    	var tooltips = new Tips(labelEl, getConditionalTooltip());
      }
      if ($defined(element['options']['infotext'])) {
    	var buttonEl = new Element('a', {
    	  'onfocus': 'focusNext(this);',
          'class': 'tooltip',
          'href': '#'+blockId+'_'+elementId,
          'onclick': 'return false;'
        });
        var imgEl = new Element('img', {
          'src': '/images/icons/information.gif'
        });
        labelEl.appendText(' ');
        imgEl.inject(buttonEl);
        buttonEl.inject(labelEl);
        new Tips(buttonEl, {
          className: 'tooltip',
          showDelay: 400,
          hideDelay: 400,
          fixed: true,
          title: function(item) {
            item = item.toString();
        	var elementId = item.substring(item.indexOf('#')+1);
        	return $(elementId+'_tooltip_title').get('html');
          },
          text: function(item) {
        	item = item.toString();
        	var elementId = item.substring(item.indexOf('#')+1);
        	return $(elementId+'_tooltip_text').get('html');
          }
        });
      }
      labelEl.inject(dtEl);
      dtEl.inject(addButtonDd, 'before');
      
      // element
      var description = element['options']['description'];
      switch (element['type']) {
        case 'multitext':
          addMultiBlockMultitext(blockId, rowNumber, elementId, description);
          break;
        case 'date':
          addMultiBlockDate(blockId, rowNumber, elementId, description);
          break;
        case 'datetime':
          addMultiBlockDatetime(blockId, rowNumber, elementId, description);
          break;
        case 'textarea':
          addMultiBlockTextarea(blockId, rowNumber, elementId, description);
          break;
        case 'checkbox':
          addMultiBlockCheckbox(blockId, rowNumber, elementId, description);
          break;
        case 'henkiloTunnus':
          addMultiBlockHenkiloTunnus(blockId, rowNumber, elementId, description);
          break;
        case 'wysiwyg':
          addMultiBlockWysiwyg(blockId, rowNumber, elementId, description);
          break;
        case 'text':
        default:
          addMultiBlockText(blockId, rowNumber, elementId, description);
          break;
      }
    }
    
	// deliminator between blocks
	var ddEl = new Element('dd', {
      'id': blockId + '_' + rowNumber + '-delim',
      'class': 'mb_delim'
      // 'text': '\u00A0' // non-breaking space
    });
    ddEl.inject(addButtonDd, 'before');
    
    multiBlocks[blockId]['rowNumber'] = parseInt(rowNumber) + 1;
  }
  
  /**
   * @param string blockId
   * @param integer rowNumber
   * @param string elementId
   * @param string description
   */
  function addMultiBlockText(blockId, rowNumber, elementId, description) {
    var addButtonDd = $(blockId);
    var ddEl = new Element('dd', {
      'id': blockId + '_' + rowNumber + '_' + elementId + '-element',
      'class': 'mb_row'
    });
    var inputEl = new Element('input', {
      'name': blockId + '[' + rowNumber + '][' + elementId + ']',
      'id': blockId + '_' + rowNumber + '_' + elementId,
      'value': '',
      'type': 'text'
    });
    inputEl.inject(ddEl);
    addMultiBlockDescription(ddEl, description);
    ddEl.inject(addButtonDd, 'before');
  }
  
  /**
   * @param string blockId
   * @param integer rowNumber
   * @param string elementId
   * @param string description
   */
  function addMultiBlockHenkiloTunnus(blockId, rowNumber, elementId, description) {
	var addButtonDd = $(blockId);
	var ddEl = new Element('dd', {
	  'id': blockId + '_' + rowNumber + '_' + elementId + '-element',
	  'class': 'mb_row'
	});
	var inputElBeginning = new Element('input', {
      'name': blockId + '[' + rowNumber + '][' + elementId + '][beginning]',
      'id': blockId + '_' + rowNumber + '_' + elementId + '-beginning',
      'value': '',
      'type': 'text',
      'class': 'personal_number_beginning'
    });
	inputElBeginning.inject(ddEl);
	ddEl.appendText(' ');
	var inputElEnding = new Element('input', {
      'name': blockId + '[' + rowNumber + '][' + elementId + '][ending]',
      'id': blockId + '_' + rowNumber + '_' + elementId + '-ending',
      'value': '',
      'type': 'text',
      'class': 'personal_number_ending'
    });
	inputElEnding.inject(ddEl);
    addMultiBlockDescription(ddEl, description, 'span');
	ddEl.inject(addButtonDd, 'before');
  }
  
  /**
   * @param string blockId
   * @param integer rowNumber
   * @param string elementId
   * @param string description
   */
  function addMultiBlockTextarea(blockId, rowNumber, elementId, description) {
    var addButtonDd = $(blockId);
    
    var ddEl = new Element('dd', {
      'id': blockId + '_' + rowNumber + '_' + elementId + '-element',
      'class': 'mb_row'
    });
    var textareaEl = new Element('textarea', {
      'name': blockId + '[' + rowNumber + '][' + elementId + ']',
      'id': blockId + '_' + rowNumber + '_' + elementId
    });
    textareaEl.inject(ddEl);
    addMultiBlockDescription(ddEl, description);
    ddEl.inject(addButtonDd, 'before');
  }
  
  /**
   * @param string blockId
   * @param integer rowNumber
   * @param string elementId
   * @param string description
   */
  function addMultiBlockDate(blockId, rowNumber, elementId, description) {
    var addButtonDd = $(blockId);
    var ddEl = new Element('dd', {
      'id': blockId + '_' + rowNumber + '_' + elementId + '-element',
      'class': 'mb_row'
    });
    var inputEl = new Element('input', {
      'name': blockId + '[' + rowNumber + '][' + elementId + ']',
      'id': blockId + '_' + rowNumber + '_' + elementId,
      'value': '',
      'size': '10',
      'maxlength': '10',
      'class': 'date',
      'type': 'text'
    });
    inputEl.inject(ddEl);
    var dateButtonEl = new Element('button', {
      'type': 'button',
      'id': 'button-' + blockId + '_' + rowNumber + '_' + elementId,
      'class': 'calendar'
    });
    dateButtonEl.inject(ddEl);
    addMultiBlockDescription(ddEl, description);
    ddEl.inject(addButtonDd, 'before');
    
    Calendar.setup({
      'inputField'  : blockId + '_' + rowNumber + '_' + elementId,             // id of the input field
      'ifFormat'    : "%d.%m.%Y",                                              // format of the input field
      'showsTime'   : false,                                                   // will display a time selector
      'button'      : 'button-' + blockId + '_' + rowNumber + '_' + elementId, // trigger for the calendar (button ID)
      'singleClick' : true,                                                    // double-click mode
      'step'        : 1                                                        // show all years in drop-down boxes (instead of every other year as default)
    });
  }
  
  /**
   * @param string blockId
   * @param integer rowNumber
   * @param string elementId
   * @param string description
   */
  function addMultiBlockDatetime(blockId, rowNumber, elementId, description) {
    var addButtonDd = $(blockId);
    var ddEl = new Element('dd', {
      'id': blockId + '_' + rowNumber + '_' + elementId + '-element',
      'class': 'mb_row'
    });
    var dateInputEl = new Element('input', {
      'name': blockId + '[' + rowNumber + '][' + elementId + '][date]',
      'id': blockId + '_' + rowNumber + '_' + elementId + '-date',
      'value': '',
      'size': '10',
      'maxlength': '10',
      'class': 'date',
      'type': 'text'
    });
    dateInputEl.inject(ddEl);
    var dateButtonEl = new Element('button', {
      'type': 'button',
      'id': 'button-' + blockId + '_' + rowNumber + '_' + elementId,
      'class': 'calendar'
    });
    dateButtonEl.inject(ddEl);
    ddEl.appendText(' ');
    var timeInputEl = new Element('input', {
      'name': blockId + '[' + rowNumber + '][' + elementId + '][time]',
      'id': blockId + '_' + rowNumber + '_' + elementId + '-time',
      'value': '',
      'size': '5',
      'maxlength': '5',
      'class': 'time',
      'type': 'text'
    });
    timeInputEl.inject(ddEl);
    addMultiBlockDescription(ddEl, description);
    ddEl.inject(addButtonDd, 'before');
    
    Calendar.setup({
      'inputField'  : blockId + '_' + rowNumber + '_' + elementId + '-date',             // id of the input field
      'ifFormat'    : "%d.%m.%Y",                                                        // format of the input field
      'showsTime'   : false,                                                             // will display a time selector
      'button'      : 'button-' + blockId + '_' + rowNumber + '_' + elementId + '-date', // trigger for the calendar (button ID)
      'singleClick' : true,                                                              // double-click mode
      'step'        : 1                                                                  // show all years in drop-down boxes (instead of every other year as default)
    });
  }
  
  /**
   * @param string blockId
   * @param integer rowNumber
   * @param string elementId
   * @param string description
   */
  function addMultiBlockCheckbox(blockId, rowNumber, elementId, description) {
    var addButtonDd = $(blockId);
    var ddEl = new Element('dd', {
      'id': blockId + '_' + rowNumber + '_' + elementId + '-element',
      'class': 'mb_row'
    });
    var inputEl = new Element('input', {
      'name': blockId + '[' + rowNumber + '][' + elementId + ']',
      'id': blockId + '_' + rowNumber + '_' + elementId,
      'value': 'true',
      'type': 'checkbox'
    });
    inputEl.inject(ddEl);
    addMultiBlockDescription(ddEl, description);
    ddEl.inject(addButtonDd, 'before');
  }
  
  /**
   * @param string blockId
   * @param integer rowNumber
   * @param string elementId
   * @param string description
   */
  function addMultiBlockWysiwyg(blockId, rowNumber, elementId, description) {
	var elementName = blockId + '[' + rowNumber + '][' + elementId + ']';
	var elementId = blockId + '_' + rowNumber + '_' + elementId;
		
	var oFCKeditor = new FCKeditor(elementName);
	oFCKeditor.Width = 420;
	oFCKeditor.Height = 300;
	
	
	oFCKeditor.ToolbarSet = 'EditaNoHtml';
	if (multiBlocks[blockId]['roleId'] == 'admin') {
      oFCKeditor.ToolbarSet = 'Edita';
    }
	
	
	oFCKeditor.Value = '';
	
	var addButtonDd = $(blockId);
	var ddEl = new Element('dd', {
	  'id': elementId + '-element',
	  'class': 'mb_row'
	});
	var divEl = new Element('div', {
	  'html': oFCKeditor.CreateHtml()
	});
	var formEl = new Element('form', {
	  'name': 'ajax',
	  'method': 'get'
	});
	var buttonEl = new Element('button', {
	  'onclick': 'javascript:fixInput(\''+elementName+'\')',
	  'type': 'button',
	  'text': 'Poista tekstistä Word-ohjauskoodit' /* @todo use translator */
	});
	buttonEl.inject(formEl);
	formEl.inject(divEl);
	divEl.inject(ddEl);
	ddEl.inject(addButtonDd, 'before');
  }
  
  /**
   * @param string blockId
   * @param integer rowNumber
   * @param string elementId
   * @param string description
   */
  function addMultiBlockMultitext(blockId, rowNumber, elementId, description) {
    var addButtonDd = $(blockId);
    
    var ddEl = new Element('dd');
    var inputEl = new Element('input', {
      'type': 'text',
      'name': blockId + '[' + rowNumber + '][' + elementId + '][]',
      'value': ''
    });
    inputEl.inject(ddEl);
    if (buttonEl) {
      buttonEl.inject(ddEl);
    }
    ddEl.inject(addButtonDd, 'before');
    
    var ddEl = new Element('dd');
    var buttonEl = new Element('button', {
      'type': 'button',
      'id': blockId + '_' + rowNumber + '_' + elementId,
      'events': {
  	    'click': function() {
    	  addMultitextLine(this)
  	    }
  	  },
  	  'text': 'Lisää'
    });
    buttonEl.inject(ddEl);
    addMultiBlockDescription(ddEl, description);
    ddEl.inject(addButtonDd, 'before');
  }

  /**
   * @param Element ddEl
   * @param string description
   */
  function addMultiBlockDescription(ddEl, description, tagName) {
	if (description != '') {
	  ddEl.appendText(' ');
	  var descEl = new Element(tagName ? tagName : 'em', {
		'class': 'hint',
		'text': description
	  });
	  descEl.inject(ddEl);
	}
  }
  
  /**
   * @param string blockId
   * @param integer rowNumber
   */
  function removeMultiBlock(blockId, rowNumber) {
	var ddEl = $(blockId + '_' + rowNumber + '-remove');
	if (ddEl) {
      ddEl.dispose();
	}
	for (elementId in multiBlocks[blockId]['elements']) {
      var element = multiBlocks[blockId]['elements'][elementId];
      var elId = blockId + '_' + rowNumber + '_' + elementId;
      switch (element['type']) {
        case 'multitext':
          removeMultiBlockMultiText(elId);
          break;
        case 'text':
        default:
          removeMultiBlockText(elId);
          break;
      }
    }
    var ddEl = $(blockId + '_' + rowNumber + '-delim');
    ddEl.dispose();
  }
    
  /**
   * @param string elId
   */
  function removeMultiBlockText(elId) {
    var dtEl = $(elId + '-label');
    dtEl.dispose();
    var ddEl = $(elId + '-element');
    ddEl.dispose();
    var ddEl = $(elId + '-error');
    if (ddEl) {
      ddEl.dispose();
    }
  }
  
  /**
   * @param string elId
   */
  function removeMultiBlockMultiText(elId) {
    var dtEl = $(elId + '-label');
    dtEl.dispose();
    var buttonEl = $(elId);
    var buttonDdEl = buttonEl.getParent();
    for (var prev = buttonDdEl.getPrevious(); !prev.getProperty('id'); prev = buttonDdEl.getPrevious()) {
      prev.dispose();
    }
    buttonDdEl.dispose();
  }

