// {{{ setup
if(typeof(SWO) != 'object')
  SWO = {}; // root of all Classes.

SWO.TOOLS = {};
SWO.SYS   = {};


var tools  = {},   // the System objects.
    sys    = {};  // the Tools objects.
    
    
SWO.TOOLS._setup = function() {
  tools.autoComplete  = new SWO.TOOLS.AutoComplete();  // 
  tools.formPicker    = new SWO.TOOLS.FormPicker();  // tol for 1-n relations (picking a form input value from another table)
  tools.tabs          = new SWO.TOOLS.Tabs();        // window tabs
  tools.editor        = new SWO.TOOLS.Editor();      // load / install/ remove WYSIWYG editor at runtime
  tools.iconDragger   = new SWO.TOOLS.IconDragger(); // drag icons from Menu to Desktop
  tools.selector      = new SWO.TOOLS.Selector();    // a form widged 
  tools.sidebar       = new SWO.TOOLS.Sidebar();     // a window Sidebar
  tools.image         = new SWO.TOOLS.Image();       // a window Sidebar
};


SWO.SYS._setup = function() {
  sys.console        = new SWO.SYS.Console(); // console for non Firefox Browsers
  sys.keys           = new SWO.SYS.Keys();   // processing keyboard input
  sys.mouse          = new SWO.SYS.Mouse();  // position of last click, what button is pressed right now
  sys.timer          = new SWO.SYS.Timer();  // timeout / interval
  sys.cssBinder      = new SWO.SYS.CssBinder();  // adding css at runtime
  sys.DOMWatchdog    = new SWO.SYS.DOMWatchdog();  // alerts global namespace Pollution at runtime
  sys.event          = new SWO.SYS.Event();         // global Event Routing (bind, unbind, trigger)
  sys.html5          = new SWO.SYS.HTML5(); // HTML5 specific functions
  sys.plugins        = new SWO.SYS.Plugins(); // check if Plugins are (Flash/reader/...) installed
  sys.tabKeyManager  = new SWO.SYS.TabKeyManager(); // makes the focus stay in a window when using the Tab key
  sys.cookie         = new SWO.SYS.Cookie();
  sys.serverPushPop  = new SWO.SYS.ServerPushPop();
  sys.format         = new SWO.SYS.Format();
};


var swmPlugins = {}; // for dynamically build- in;


function Void() { /* do nothing */ }

// }}}


// {{{ TOOLS


/// {{{ IconDragger


SWO.TOOLS.IconDragger = function() {
  
  var self = this,
      _pos,
      _unmoved,
      _title,
      _swmObject,
      _image,
      _width,
      _height,
      _obj;
  
  
  this.add = function(obj) {
    $(obj).mousedown(self.savePos);
    $(obj).enableDrag(startDrag, drag, stopDrag);
  };
  
  this.savePos = function(e) {
    _pos = sys.mouse.getPos(e);
  };
  
  function startDrag(x, y, e) {
    _unmoved = true;
  }
  
  function drag(mdx, mdy, e) {
    if(_unmoved) {
      initDrag(this);
      _unmoved = false;
    }
    _pos.x += mdx;
    _pos.y += mdy;
    _obj.xMoveBy(mdx, mdy);
  }
  
  function stopDrag(x, y, e) {
    if(_obj) {  _obj.remove(); _obj = false; }
    return _unmoved;
  }
  
  function initDrag(obj) {
    _title = $(obj).text().replace(/^ */,'').replace(/ *$/,'');
    _swmObject = $(obj).children('a').attr('object');
    _image  = $(obj).children('a').attr('image');
    _width  = $(obj).children('a').attr('width');
    _height = $(obj).children('a').attr('height');
    $(document).bind('mouseup', addIcon);
    var c = $('<img src="/templates/CMS/standard/images/drop_down_icon.png" id="theDragImage" />');
    c.addClass('dragElement');
    c.xMoveTo(_pos.x + 5, _pos.y + 17);
    c.appendTo('#desktop');
    _obj = c;
  }
  
  function addIcon(e) {
    if(e.target == $('#desktop')[0]) {
      var img = (_image == 'none') ? '/templates/images/default_icon_48x48.png' : '/templates/images/' + _image.replace(/16/g, '48');
      _pos.x -= 50; 
      _pos.y -= 25;
      swm.d.newIcon(img, '/modules/CMS/CMS_do.php?__id=' + _swmObject, _title, _width, _height, _pos);
    }
    $(document).unbind('mouseup', addIcon);
  }
  
};


// }}}


// {{{ FormPicker


SWO.TOOLS.FormPicker = function () {
  
  var self     = this,
      _stack   = [],
      _mode    = 'client';
  
  
  this.openServer = function(url, backUrl, stay) {
    _stack.push({mode:'server', backUrl:backUrl, stay:stay});
    Loader.request(url);
  };
  
  this.getCallback = function() {
    op = _stack[_stack.length - 1];
    if(!op) return;
    return op.backUrl || op.callback;
  };
  
  this.openClient = function(callback, stay) {
    _stack.push({mode:'client', callback:callback, stay:stay});
  };
  
  
  this.open = function(field, url, callback) {
    _stack.push({mode:'input', field:field, callback:callback});
    Loader.request(url);
  };
  
  
  this.send = function(id, value, name, object) {
    var par, op = _stack.pop();
    
    if(!op) return;
    
    switch(op.mode) {
      case 'client':
        op.callback(id, value, name, object);
        break;
      case 'input':
        if(op.field) {
          op.field.value = value || id;
          $(op.field).trigger('change');
        }
        if(op.callback)
          op.callback(id, value, name, object);
        break;
      case 'server':
        par = {id:id};
        if((typeof name).match(/string|number/))     par.name     = encodeURI(name);
        if((typeof value).match(/string|number/))    par.value    = encodeURI(value);
        if((typeof object).match(/string|number/))   par.object   = encodeURI(object);
        Loader.call(op.backUrl, par);
        break;
    }
    if(!op.stay) swm.wm.getActive().close();
    if(op.stay) _stack.push(op);
  };
  
  this.initTable = function(table) {
    if(table.pickerInstalled) return true;
    $('TR', table).initClasses().where(function() { return typeof this.pId != 'undefined';}).bind('dblclick', function(){
      self.send(this.pId, this.pValue, this.pName, this.oId);
    }).css('cursor', 'pointer');
    table.pickerInstalled = true;
  };
  
};


/// }}}


/// {{{ LiveSearch


SWO.TOOLS.AutoComplete = function () {
  
  var self = this;
  
  this.init = function(input) {
    
    $(input)
      .initClasses()
      .xBind('type', function() {
        
        var par = {fieldValue:this.value,
                   fieldName: this.name,
                   formId:    this.form.getAttribute('id')};
        
        if(this.field) {
          assert(input.form[this.field], 'LiveSearch: field "' + this.field + '" does not exist.');
          par.fieldValue = input.form[this.field].value;
        }
        
        Loader.call(this.url, par, function(data) {
          self.suggest(input, data);
        });
        
        this.onFocusOut = function() {
          if($(this).attr('onFocusOutUrl'))
            Loader.call($(this).attr('onFocusOutUrl'), {fieldValue:this.value, formId:par.formId});
        };
        
      });
  };
  
  
  this.suggest = function(obj, value) {
    var pos = obj.value.length;
    if(value && value.substring(0, pos).toUpperCase() == obj.value.toUpperCase()) {
      obj.value = value;
      if(pos > 0)
        setCursor(obj,pos);
    }
  };
  
  
  function setCursor(obj, pos) {
          obj.selectionStart = pos;
      obj.selectionEnd   = obj.value.length; //alles markieren // pos; 
      }
  
  
  function getCursor(obj) {
          return obj.selectionStart;
      }
  
  
  function sendRequest(obj, url) {
    url = url + '&fieldValue=' + obj.value + '&fieldName=' + obj.name + '&formId=' + obj.form.getAttribute('id');
    Loader.request(url);
  }
  
  
  function getCode(obj) {
    return obj.form.getAttribute('id') + '__' + obj.name;
  }
  
};

SWO.TOOLS.LiveSearch = function (element) {
  
  $.event.add(element, 'keyup', startTimeoutAction);
  $.event.add(element, 'focus', search);
  $.event.add(element, 'change', function() { currentValue = this.value; });
  $.event.add(element, 'blur', function() { table.hide(); hasFocus = false; currentValue = this.value; });
  
  var table = $(document.createElement('table'));
  var hasFocus = false;
  var timeoutAction = null;
  var currentValue = element.value;
  var displayColumns = {};
  
  if(element.hasAttribute('livesearch-columns') == true)
    element.getAttribute('livesearch-columns').split(' ').each(function(i) {
      displayColumns[this] = 1;
    });
  
  table.addClass('liveSearchTable listing');
  table.css('top', element.offsetTop + element.offsetHeight + 'px');
  table.css('left', element.offsetLeft + 'px');
  
  element.liveSearchTable = table;
  element.parentNode.insertBefore(table[0], element);
  
  function startTimeoutAction() {
    
    if(timeoutAction != null) {
      
      window.clearTimeout(timeoutAction);
      timeoutAction = null;
      
    }
    
    timeoutAction = window.setTimeout(search, 500);
    
  }
  
  function search() {
    
    if(element.value != currentValue) {
      
      currentValue = element.value;
      
      hasFocus = true;
      
      $.getJSON(element.getAttribute('livesearch'), {value:element.value}, function(result) {
        
        if(hasFocus == true) {
          
          var thead = document.createElement('thead');
          var tbody = document.createElement('tbody');
          
          for(i in result.header)
            thead.appendChild(document.createElement('th')).appendChild(document.createTextNode(result.header[i]));
              
          element.liveSearchTable.children().remove();
          element.liveSearchTable.append(thead);
          element.liveSearchTable.append(tbody);
          
          result.data.each(function() {
            
            var tr = tbody.appendChild(document.createElement('tr'));
            
            $.event.add(tr, 'mousedown', pick);
            
            for(i in this) {
              
              if(result.reference_pick_key && result.reference_pick_key == i)
                tr.setAttribute('reference-value', this[i]);
              
              if(result.pick_key == i)
                tr.setAttribute('livesearch-value', this[i]);
              
              if(result.header[i])
                tr.appendChild(document.createElement('td')).appendChild(document.createTextNode(this[i]));
              
            };
            
          });
          
          if(result.data.length > 0 && table.is(':visible') == false)
            table.show();
          
        }
        
      });
      
      function pick(e) {
        
        element.value = e.currentTarget.getAttribute('livesearch-value');
        currentValue = element.value;
        
        if(element.hasAttribute('pickup-reference'))
          document.getElementById(element.getAttribute('pickup-reference')).value = e.currentTarget.getAttribute('reference-value');
        
        table.hide();
        
      }
      
    }
    
  }
  
};


/// }}}


/// {{{ Tabs


SWO.TOOLS.Tabs = function() {
  
  var self = this;
  
  self.init = function(tabList) {
    
    var tId = $(tabList).initClasses()[0].tId;
    $('.tab_a', tabList)
      .initClasses()
      .xBind('safeClick', function() {
        self.show(tId + '_' + this.nr, this);
      })
      .each(function(){
        if(this.url)
          Loader.call(this.url);
      });
  };
  
  
  this.show = function(id, a) {
    
    assert((typeof id) == 'string', 'error in tools.tabs.show: id is not a string');
    var _a = $(a);
    if(_a.hasClass('tabDisabled')) return false;
    var tabsId = id.split('_')[0];
    
    if(a.reloadUrl)
      Loader.call(a.reloadUrl);
    
    $('#' + tabsId + ' a').removeClass('tabActive');
    _a.addClass('tabActive');
    
    $('#' + tabsId + '_layers').children().css('display', 'none');
    $('#' + id).css('display', '');
    swm.wm.getActive().onTabChange(a.name);
  };
};


/// }}}


/// {{{ Editor


SWO.TOOLS.Editor = function() {
  
  var self = this,
      mceLoading = false,
      callbacks = [],
      cssStack= {},
      mediaId = 842,
      mceSettings = {
                     simple: {
                              forced_root_block : 'div',
                              strict_loading_mode: true,
                              mode: "none",
                              dialog_type: "window",
                              language: "en",
                              theme: "simple",
                              relative_urls: false,
                              convert_urls: false,
                              remove_script_host: false,
                              verify_html: false,
                              remove_linebreaks: false,
                              convert_fonts_to_spans: true,
                              login_url: '/modules/CMS/CMS_do.php?',
                              entity_encoding: 'raw'}, 
                     advanced: {
                                forced_root_block : 'div',
                                strict_loading_mode: true,
                                mode: "none",
                                dialog_type: "window",
                                language: "en",
                                theme: "advanced",
                                relative_urls: false,
                                convert_urls: false,
                                remove_script_host: false,
                                verify_html: false,
                                remove_linebreaks: false,
                                convert_fonts_to_spans: true,
                                file_browser_callback: 'tinyMCEFileBrowserCallback',   // plugin: inlinepopups,
                                init_instance_callback: 'tinyMCEInitInstanceCallback',
                                plugins: "inlinepopups, safari,pagebreak,style,table,advimage,advlink,insertdatetime,media,searchreplace,print,contextmenu,paste,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,xtra",
                                theme_advanced_buttons1: "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,|,search,|,bullist,numlist,|,outdent,indent,|,link,unlink,anchor,image,code",
                                theme_advanced_buttons2: "undo,redo,|,pastetext,pasteword,|,insertdate,inserttime,|,forecolor,backcolor,|,table,|,visualaid,|,sub,sup,|,charmap,media,|,print,|,fullscreen,|,styleprops,|,cite,attribs,|,xtra",
                                theme_advanced_buttons3: "",
                                theme_advanced_buttons4: "",
                                theme_advanced_toolbar_location: "top",
                                theme_advanced_toolbar_align: "left",
                                theme_advanced_statusbar_location: "bottom",
                                theme_advanced_resizing: true,
                                login_url: '/modules/CMS/CMS_do.php?',
                                entity_encoding: 'raw'}};
  
  // // load Editor after n seconds when CMS is loaded.
  // sys.timer.timeout(20000, function(){ requireTinyMCE('advanced'); });
  
  this.css = function(id, css) {
    // console.log('mce css: '+id+' to '+css);
    var instance = tinyMCE.get(id);
    if(!instance) {
      // console.log('mcs css: instance '+id+' not there, to stack');
      cssStack[id] = css;
      return;
    }
    
    cssStack[id] = null;
    
    var wd   = instance.getWin().document,
        head = wd.getElementsByTagName('HEAD')[0];
        
    var cssLink = wd.getElementById('cssLink');
    
    if(cssLink) {
      head.removeChild(cssLink);
    }
    
    if(true) {
      
      $('#menu_'+id+'_'+id+'_styleselect_menu_tbl').find('tr').dump('tiny').each(function() {
        this.parentNode.removeChild(this);
      });
      
      cssLink = wd.createElement('link');
      cssLink.setAttribute('rel', 'stylesheet');
      cssLink.setAttribute('id', 'cssLink');
      head.appendChild(cssLink);
      
    }
    
    $(cssLink).attr('href', css).attr('mce_href', css);
    //instance.render();
    instance.nodeChanged();
    
  };
  
  
  // install a new Editor (called from dom.layer)
  this.add = function(elem, config, css) {
    
    requireTinyMCE(config, function() {
      
      assert(tinyMCE.get(elem.id) == null,'initWYSIWYG, editor already exists');
      
      var submitFunction = elem.form.onsubmit || function() {};
      
      elem.form.onsubmit = function () {
        
        tinyMCE.triggerSave();
        submitFunction.call(this);
        
        return false;
        
      };
      
      var ed = new tinymce.Editor(elem.id, mceSettings[elem.mceTheme]);
      
      ed.render();
      
      if(css)
       self.css(elem.id, css);
     
    });
    
  };
  
  
  this.remove = function (elem) {
    if(!tinyMCE) return;
    tinyMCE.execCommand('mceRemoveControl', false, elem.id);
    cssStack[elem.id] = null;
  };
  
  
  function requireTinyMCE(config, callback) {
    callback = callback || function(){};
    if(typeof(tinyMCE) !== 'object' && !mceLoading) {
      mceLoading = true;
      callbacks.push(callback);
      // insert script tag
      var a = document.createElement('script');
      a.setAttribute('type', 'text/javascript');
      a.setAttribute('src',  '/editors/tinymce/jscripts/tiny_mce/tiny_mce_src.js');
      document.getElementsByTagName('HEAD')[0].appendChild(a);
      
      // polling for tinyMCE object
      sys.timer.interval(250, function(){
        if(typeof(tinyMCE) !== 'object') return;
        this.clear();
        mceLoading = false;
        tinymce.dom.Event.domLoaded = true;
        callbacks.each(function(){ this(); });
      });
      
    } else if(mceLoading) {
      callbacks.push(callback);
    } else {
      callback();
    }
  }
  
  window.tinyMCEFileBrowserCallback = function(fieldName, url, type , win) {
    
    if(type == 'file') {
      
      Loader.call('/modules/CMS/CMS_do.php?__action=pickerUrlWindow&__id=820&__picker=path&picker=path');
      
      tools.formPicker.openClient(function(data) {
        var element = win.document.getElementById(fieldName);
        element.value = decodeURIComponent(data.url);
        element.onchange();
      });
      
    } else if(type == 'image') {
      
      Loader.call('/modules/CMS/CMS_do.php?__id=' + mediaId + '&__picker=1');
      
      tools.formPicker.openClient(function(value) {
        var element = win.document.getElementById(fieldName);
        element.value = decodeURIComponent(value);
        element.onchange();
      });
      
    }
    
  };
  
  window.tinyMCEInitInstanceCallback = function(inst) {
    var css = cssStack[inst.editorId];
    if(!css) return;
      self.css(inst.editorId, css);
  };
  
};

//
SWO.TOOLS.Selector = function() {
  
  var self = this;
  
  self.init = function(div) {
    
    var div_jq = $(div);
    
    div_jq.initClasses();
    
    var p = $('p', div);
    var source = $('.source', div);
    var target = $('.target', div);
    var mousedown = function(p_elm) {
      
      p_elm.swoSelected = false;
      
      $(p_elm).mousedown(function() {
        $(this).siblings('p').each(function() { this.swoSelected = false; this.style.backgroundColor = ''; });
        this.style.backgroundColor = '#94D8E4';
        this.swoSelected = true;
      });
      
    };
    
    p.dblclick(function () {
      if($(this).parent().get(0).className == 'source') {
        target.prepend('<input id="' + this.id + '" class="hidden" type="hidden" value="' + this.innerHTML + '" name="' + $(div).attr('name') + '[' + this.id + ']"/>');
        target.prepend(this);
        mousedown(this);
      } else {
        this.style.backgroundColor = '';
        $(this).unbind('mousedown');
        source.prepend(this);
        $('input[id=\'' + this.id + '\']', target).remove();
      }
    });
    
    div_jq.find('.sort-panel img').click(function() {
      
      var p_elm_jq = target.find('p').where(function() { return this.swoSelected == true; });
      
      if(p_elm_jq.length == 1) {
        
        var p_elm = p_elm_jq.get(0);
        
        if(this.className == 'up') {
          
          var input = p_elm_jq.next('input');
          var prev_p = p_elm_jq.prev().prev();
          
          if(prev_p.length != 0) {
            
            prev_p.before(p_elm_jq);
            p_elm_jq.after(input);
            
          }
          
        } else if(this.className == 'down') {
          
          var input = p_elm_jq.next('input');
          var next_input = input.next().next();
          
          if(next_input.length != 0) {
            
            next_input.after(p_elm_jq);
            p_elm_jq.after(input);
            
          }
          
        }
        
      }
      
    });
    
    target.find('p').each(function() { mousedown(this); });
    
  };
  
};

SWO.TOOLS.Sidebar = function() {
  
  var self = this;
  
  self.init = function(table) {
    
    var win  = dom.layer.get(table).getWin(),
        cntl = dom.layer.get(table).getContentLayer();
    
    win.listen('resize', check);
    check();
    
    function check() {
      $(table).css('height', $(cntl).css('height'));
    }
    
  };
  
};

SWO.TOOLS.BalloonTip = function(element, content) {
  
  var div = null;
  var desktop = document.getElementById('desktop');
  
  this.remove = function() {
    
    $.event.remove(element, 'mouseover', mouseover);
    $.event.remove(element, 'mouseout', mouseout);
    
  };
  
  this.setContent = function(str) {
    content = str;
  };
  
  function mouseover(e) {
    
    if(content) {
        
      // Icon position
      var target = $(this);
      var tpos = target.position();
      
      // Help dialog
      div = document.createElement('div');
      
      div.className = 'balloon-tip';
      div.style.display = 'block';
      div.style.width = 'auto';
      div.style.left = '-1000px';
      div.style.top = '-1000px';
      div.innerHTML = content;
      
      desktop.appendChild(div);
      
      // Desktop size
      var deskw = desktop.offsetWidth;
      var deskh = desktop.offsetHeight;
      
      // Content size
      var contentw = div.offsetWidth;
      var contenth = div.offsetHeight;
      
      if(contentw > 400)
        contentw = 400;
      
      var scrollTop = 0;
      var scrollLeft = 0;
      
      var getScrollValues = function(elm) {
        
        scrollTop += elm.scrollTop;
        scrollLeft += elm.scrollLeft;
        
        if(typeof elm.parentNode != 'undefined' && typeof elm.parentNode.scrollTop != 'undefined')
          getScrollValues(elm.parentNode);
        
      };
      
      div.style.left = (tpos.left - (contentw + 10) - scrollLeft)  +'px';
      div.style.width = contentw +'px';
      
      getScrollValues(element);
      
      if((tpos.left + contentw - scrollLeft) < deskw) {
        
        div.style.left = (tpos.left + 20 - scrollLeft)  + 'px';
        
        if((tpos.top + contenth - scrollTop + 70) < deskh)
          div.style.top = (tpos.top + 20 - scrollTop) + 'px';
        else
          div.style.top = (tpos.top - (contenth + 10) - scrollTop) +'px';
        
      } else {
        
        div.style.left = (tpos.left - (contentw + 10) - scrollLeft)  +'px';
        
        if((tpos.top + contenth - scrollTop + 70) < deskh)
          div.style.top = (tpos.top + 20 - scrollTop) +'px';
        else
          div.style.top = (tpos.top - (contenth + 10) - scrollTop) +'px';
        
      }
    
    }
    
  }
  
  function mouseout() {
    
    if(div != null) {
      div.parentNode.removeChild(div);
      div = null;
    }
    
  }
  
  $.event.add(element, 'mouseover', mouseover);
  $.event.add(element, 'mouseout', mouseout);
  
};

/// }}}


/// {{{ Image

SWO.TOOLS.Image = function() {
  
  this.grayscale = function(image, width, height) {
    
    if(typeof image != 'object') {
      imgObj = new Image();
      imgObj.src    = image;
      imgObj.width  = width;
      imgObj.height = height;
    } else {
      imgObj = image;
    }
    
    var canvas = document.createElement('canvas');
    var canvasContext = canvas.getContext('2d');
    
    var imgW = imgObj.width;
    var imgH = imgObj.height;
    
    canvas.width = imgW;
    canvas.height = imgH;
    
    canvasContext.drawImage(imgObj, 0, 0);
    
    var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);
    
    for(var y = 0; y < imgPixels.height; y++){
       for(var x = 0; x < imgPixels.width; x++){
          var i = (y * 4) * imgPixels.width + x * 4;
          var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
          imgPixels.data[i] = avg;
          imgPixels.data[i + 1] = avg;
          imgPixels.data[i + 2] = avg;
       }
    }
    canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
    
    return canvas.toDataURL();
      
  };
  
  
  this.lighter = function(image, width, height) {
    
    if(typeof image != 'object') {
      imgObj = new Image();
      imgObj.src    = image;
      imgObj.width  = width;
      imgObj.height = height;
    } else {
      imgObj = image;
    }
    
    var canvas = document.createElement('canvas');
    var canvasContext = canvas.getContext('2d');
    
    var imgW = imgObj.width;
    var imgH = imgObj.height;
    
    canvas.width = imgW;
    canvas.height = imgH;
    
    canvasContext.drawImage(imgObj, 0, 0);
    
    var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);
    
    for(var y = 0; y < imgPixels.height; y++){
       for(var x = 0; x < imgPixels.width; x++){
          var i = (y * 4) * imgPixels.width + x * 4;
          var avg = 350;
          imgPixels.data[i] = avg;
          imgPixels.data[i + 1] = avg;
          imgPixels.data[i + 2] = avg;
       }
    }
    canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
    
    return canvas.toDataURL();
      
  };
  
  
  this.invert = function(image, width, height) {
    
    if(typeof image != 'object') {
      imgObj = new Image();
      imgObj.src    = image;
      imgObj.width  = width;
      imgObj.height = height;
    } else {
      imgObj = image;
    }
    
    var canvas = document.createElement('canvas');
    var canvasContext = canvas.getContext('2d');
    
    var imgW = imgObj.width;
    var imgH = imgObj.height;
    
    canvas.width = imgW;
    canvas.height = imgH;
    
    canvasContext.drawImage(imgObj, 0, 0);
    
    var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);
    
    for(var y = 0; y < imgPixels.height; y++){
       for(var x = 0; x < imgPixels.width; x++){
          var i = (y * 4) * imgPixels.width + x * 4;
          imgPixels.data[i]     = imgPixels.data[i + 2];
          imgPixels.data[i + 2] = imgPixels.data[i];
       }
    }
    canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
    
    return canvas.toDataURL();
      
  };
  
  
};


/// }}}


// {{{ SYS


/// {{{ Console
SWO.SYS.Console = function() {
  
  this.init = function(){
    if(typeof console == 'undefined' || typeof console.log == 'undefined') {
              console = new DummyConsole();
          }
  };
  
  
  function MyConsole() {
  }
  
  
  MyConsole.prototype = {
    _cnt:'<p style="border-bottom: 1px solid black;"><a onclick="console.clear();" >Clear</a></p>',
    log:function(msg) {
     this._black(msg);
    },
    info:function(msg) {
     this._black('<b>info: </b>'+msg);
    },
    warn:function(msg) {
     this._black('<b>warning: </b>'+msg);
    },
    error:function(msg) {
     this._red('<b>Error: </b>'+msg);
    },
    clear:function(){
      this._cnt = '<p style="border-bottom:1px solid black;"><a onclick="console.clear(); ">Clear</a></p>';
      this._display();
    },
    _black:function(msg) {
      msg = msg.toString().replace(/</g,'&lt;').replace(/>/g,'&gt;');
      this._cnt += '<p style="border-bottom:1px solid black;"><pre>'+msg+'</pre></p>';
      this._display();
    },
    _red:function(msg) {
      msg = msg.toString().replace(/</g,'&lt;').replace(/>/g,'&gt;');
      this._cnt += '<p style="border-bottom:1px solid red; color: red;"><pre>'+msg+'</pre></p>';
      this._display();
    },  
    _display:function() {
      if((typeof swm).substr(0,2) != 'un') {
        var wnd = swm.wm.getWindow('console');
        if(wnd) {
         // wnd.focus();
        } else {
          wnd = swm.wm.newWindow({width:800,height:600}, null, 'console', '', true, {url:'', requestWinId:'desktop'});
          wnd.setTitle('Console');
        }
        wnd.setContent(this._cnt);
      } else {
       // alert(this._cnt);
      }
    }
  };
  
  function DummyConsole() {}
  
  DummyConsole.prototype = {
    log:function(){},
    info:function(){},
    warn:function(){},
    error:function(){}
  };
  
};
/// }}}


/// {{{ Keys
SWO.SYS.Keys = function() {
  
  var self = this,
      _shiftDown = false,
      _ctrlDown  = false,
      _altDown   = false,
      _charTable = {9:'Tab', 37:'LEFT', 38:'UP', 39:'RIGHT', 40:'DOWN',
                    112:'F1', 113:'F2', 114:'F3', 115:'F4',
                    116:'F5', 117:'F6', 118:'F7', 119:'F8',
                    120:'F9', 121:'F10', 122:'F11', 123:'F12' };
      
      // fix for shiftDown
      _shiftCharTable = {222:'2', 191:'7', 55:'6', 48:'9', 57:'8'};
  
  this.onKeyDown = function(evt) {
    if((typeof swm_cms_desktop).match(/^un/)) return; // disable for login screen
    switch (evt.keyCode) {
      case 16: // shift
        _shiftDown = true;
        break;
      case 17: // ctrl
        _ctrlDown = true;
        break;
      case 18: // alt
        _altDown = true;
        break;
    }
    processKeyEvent(evt.keyCode, 'Down', evt);
  };
  
  this.onKeyUp = function(evt) {
    if((typeof swm_cms_desktop).match(/^un/)) return; // disable for login screen
    switch (evt.keyCode) {
      case 16: // shift
        _shiftDown = false;
        break;
      case 17: // ctrl
        _ctrlDown = false;
        break;
      case 18: // alt
        _altDown = false;
        break;
    }
    processKeyEvent(evt.keyCode, 'Up', evt);
  };
  
  this.onKeyPress = function(evt) {
    if((typeof swm_cms_desktop).match(/^un/)) return; // disable for login screen
    processKeyEvent(evt.keyCode, 'Press', evt);
  };
  
  
  this.shiftDown = function() {
    return _shiftDown;
  };
  this.ctrlDown = function() {
    return _ctrlDown;
  };
  this.altDown = function() {
    return _altDown;
  };
  
  function processKeyEvent(code, mode, evt) {
    var as = '', ch = String.fromCharCode(code);
    ch = self.shiftDown() ? ch.toUpperCase() : ch.toLowerCase();
    if(self.ctrlDown()) as += 'CTRL';
    if(self.altDown())  as += 'ALT';
    if(self.shiftDown())  as += 'SHIFT';
    if(as) as = '_'+as;
    if(code in _charTable)
      ch = _charTable[code];
    else if(self.shiftDown() && code in _shiftCharTable)
        ch = _shiftCharTable[code];
    else if(!ch.match(/[0-9A-Za-zäöüÄÖÜß]/))
      return;
    var string = 'onKey'+mode+as+'_'+ch;
    var win = swm.wm.getActive();
    if(!win) return;
    win.onKeyEvent(string, code, mode, ch, evt);
  }
  
  $(document).bind('keydown', self.onKeyDown).bind('keyup', self.onKeyUp).bind('keypress', self.onKeyPress);
  
};
/// }}}


/// {{{ Mouse
// sys.mouse holds always the mousePosition of the last Click
/**
 *  use:
 *  sys.mouse.getLastClickPosition()  // the page coordinates of the last click
 *  sys.mouse.leftButtonDown()        // wether the left Mousebutton is hold down now
 *  sys.mouse.rightButtonDown()
 */

SWO.SYS.Mouse = function() {
  var x = 0,
      y = 0,
      leftDown = false,
      rightDown = false;
      
  this.set = function(e) {
    var pos = this.getPos(e);
    x = pos.x;
    y = pos.y;
  };
  
  this.setDown = function(e) {
    this.isRightClick(e) ? (rightDown = true) :
                           (leftDown  = true);
  };
  
  this.setUp = function(e) {
    this.isRightClick(e) ? (rightDown = false) :
                           (leftDown  = false);
  };
  
  this.getLastClickPosition = function() {
     return {x:x, y:y};
  };
  
  this.getPos = function(e) {
    var pos = {x:0, y:0};
      pos.x = e.pageX;
    pos.y = e.pageY;
     return pos;
  };
  
  this.isRightClick = function(e) {
    return    (e.type && e.type == "contextmenu")
           || (e.button && e.button == 2) 
           || (e.which && e.which == 3);
  };
  
  this.isLeftClick = function(e) {
    return ! this.isRightClick(e);
  };
  
  this.leftButtonDown = function(){
    return leftDown;
  };
  
  this.rightButtonDown = function(){
    return rightDown;
  };
};

// save MousePosition on Click (see also xStopPropagation!)
$.event.add(document, 'click', function(e) { sys.mouse.set(e); });
$.event.add(document, 'mousedown', function(e) { sys.mouse.setDown(e); });
$.event.add(document, 'mouseup', function(e) { sys.mouse.setUp(e); });

/// }}}


/// {{{ Timer
SWO.SYS.Timer = function() {
  
  var counter = 0;
  var functions = {};
  var objects   = {};
  var self = this;
  
  this.timeout = function(delay, f) {
    var ticket = this._getTicket();
    functions[ticket] = f;
    var timeout = window.setTimeout('sys.timer._call(' + ticket + ')',delay);
    timeout.clear = function() {
      window.clearTimeout(this);
    };
    return timeout;
  };
  
  this.interval = function(delay, f, now) {
    var ticket = this._getTicket();
    functions[ticket] = f;
    var obj = objects[ticket] = {};
    obj.i = 0;  // counter
    var interval = window.setInterval('sys.timer._call(' + ticket + ')',delay);
    obj.clear = function(){
      window.clearInterval(interval);
    };
    if(now) {
      f.apply(obj);
    }
    return obj;
  };
  
  this._getTicket = function() {
    return counter++;
  };
  
  this._call = function(ticket) {
    var f = functions[ticket],
        obj = objects[ticket];
    if(obj){
      obj.i++;
      f.apply(obj);
    } else {
      f();
    }
  };
  
};
/// }}}


/// {{{ Cookie

SWO.SYS.Cookie = function() {
  document.cookie = "resolution=" + screen.width + "x" + screen.height;
  document.cookie = "shade=" + screen.colorDepth; 
};

/// }}}


/// {{{ CssBinder
SWO.SYS.CssBinder = function() {
  
  var self      = this,
      fileAdded = {},
      cssAdded  = {};
  
  
  this.add = function(href) {
    if(fileAdded[href]) return;
    var a = document.createElement('link');
    a.setAttribute('rel', 'stylesheet')
    a.setAttribute('type', 'text/css');
    a.setAttribute('href', href);
    document.getElementsByTagName('HEAD')[0].appendChild(a);
    fileAdded[href] = true;
  };
  
  // Not for Internet Explorer
  this.addDirect = function(css) {
    var hash = css.hash();
    if(cssAdded[hash]) return;
    // console.log('addDirect: '+css);
    
    if (navigator.appName != 'Microsoft Internet Explorer') {
      
      a = document.createElement('style');
      a.setAttribute('type', 'text/css');
      a.appendChild(document.createTextNode(css));
      document.getElementsByTagName('HEAD')[0].appendChild(a);
      
    }
    
    cssAdded[hash] = true;
  };
  
};
/// }}}

/// {{{ DOMWatchdog
// alert on global namespace pollution.
SWO.SYS.DOMWatchdog = function() {
  
  var items = {};
    
  function init(){
    var n;
    for(n in window) {
      items[n] = true;
    }
  }
  
  function check() {
    var n;
    for(n in window) {
      if(!(n in items)) {
        if((typeof(console) === 'object') && typeof(console.log) === 'function')
          console.log('DOM pollution: ' + n + ' (' + (typeof window[n]) + ') ' +
                      ' added to global namespace. (uninitialized variable?)');
        items[n] = true;
      }
    }
  }
  
};
/// }}}


// Event Hub
SWO.SYS.Event = function() {
  
  var events = {};
  
  this.bind = function(e, f){
    events[e] = events[e] || [];
    events[e].push(f);
  };
  
  this.unBind = function(e, f){
    if(events[e]) 
      events[e].remove(f);
  };
  
  this.trigger = function(e, data){
    if(events[e])
      events[e].each(function(){
        this(data);
      });
  };
};



/// {{{ Plugins (check for Flash/Reader/etc.)
SWO.SYS.Plugins = function() {
  
  var mimeTypes = {flash:['application/x-shockwave-flash'],
                   pdf:  ['application/pdf']};
  
  var activeXObjectNames = {flash:['ShockwaveFlash.ShockwaveFlash'],
                            pdf:  ['AcroPDF.PDF', 'PDF.PdfCtrl']};
  
  this.isInstalled = function(name) {
    
    return true;
    
    if(window.ActiveXObject) {
      
      var length = activeXObjectNames[name].length;
      
      for(var i = 0; i != length; i++) {
        
        try {
          new ActiveXObject(activeXObjectNames[name][i]);
        } catch(e) {
          return false;
        }
        
        return true;
        
      }
      
    } else {
      
      switch(name) {
        
        case 'java':
          return !!navigator.javaEnabled();
        default:
          
          if(mimeTypes[name]) {
            
            var plugin = navigator.mimeTypes[mimeTypes[name]];
            return plugin && plugin.enabledPlugin;
            
          }
          
      }
      
    }
    
  };
  
};
/// }}}


/// {{{ HTML5 specific functions
SWO.SYS.HTML5 = function() {
  
  this.supportsWebStorage = function() {
    return ('localStorage' in window) && window['localStorage'] !== null;
  };
  
  this.localStorage = {
    
    set: function(key, val) {
      window.localStorage.setItem(key, val);
    },
    
    get: function(key) {
      return window.localStorage.getItem(key);
    },
    
    
    add: function(key, val) {
      var storage = window.localStorage.getItem(key);
      window.localStorage.setItem(key, storage + val);
    },
    
    remove: function(key) {
      window.localStorage.removeItem(key);
    }
    
  };
  
};
/// }}}


/// {{{ TabKeyManager

// makes the Focus stay (circle) inside a Window/Tab when using the Tab key.
SWO.SYS.TabKeyManager = function() {
  
  var node, elem;
  
  this.init = function(layer) {
    var forms = layer.getElementsByTagName('FORM'),
        i = 0, j = 0,  form, elem;
    while(form = forms[i++]) {
      extendForm(form);
    }
    this.route(layer);
  };
  
  this.route = function(layer) {
    layer = dom.layer.get(layer).getContentLayer() || layer; // the outer Window Content Layer (if it is inside a Window)
    var forms = getVisible(layer.getElementsByTagName('FORM'));
    forms.each(function(){
      this.visible = getVisible(this.elements);
    }).each(function(){
      setFormNextPrev(this, forms);
    }).each(function(){
      setElementsNextPrev(this.visible);
    });
    if(forms[0] && forms[0].visible[0])
      forms[0].visible[0].focusIfInRange();
  };
  
  
  function extendForm(form) {
    if(form.tkmExtended) return;
    form.isVisible = _isVisible;
    var j=0, elem;
    while(elem = form.elements[j++]) {
      elem.isVisible = _isVisible;
      elem.isElement = _isElement;
      if(elem.isElement())
        extendElement(elem);
    }
    form.tkmExtended = true;
  }
  
  
  function getVisible(all) {
    var j=0, elem, visible = [];
    while(elem = all[j++]) {
      if(typeof elem.isVisible == "function" && elem.isVisible()) {
        visible.push(elem);
      }
    }
    return visible;
  }
  
  function _isElement() {
    var node = this;
    if((typeof(node.type) == 'string' &&
        node.type.toUpperCase() == 'HIDDEN') ||
        node.tagName.toUpperCase() == 'FIELDSET')
      return false;
    return true;
  }
  
  function _isVisible() {
    var node = this;
    if((typeof(node.type) == 'string' &&
        node.type.toUpperCase() == 'HIDDEN') ||
        node.tagName.toUpperCase() == 'FIELDSET')
      return false;
    while(node) {
      if(node.style && (node.style.visibility == 'hidden' ||
         node.style.display == 'none' )) {
        return false;
      }
      node = node.parentNode;
    }
    return true;
  }
  
  
  function setElementsNextPrev(elems) {
    if(!elems.length)
      return;
    for(var i = 1; i < (elems.length-1); i++) {
      elems[i].prev = elems[i-1];
      elems[i].next = elems[i+1];
    }
    var m = elems.length - 1;
    elems[0].next = elems[1] || elems[m].form.next.visible[0];
    elems[0].prev = elems[0].form.prev.visible[elems[0].form.prev.visible.length-1];
    
    elems[m].next = elems[m].form.next.visible[0];
    elems[m].prev = elems[m-1] || elems[0].form.prev.visible[elems[0].form.prev.visible.length-1];
  }
  
  
  function setFormNextPrev(myForm, forms) {
    //alert('forms='+forms+' length='+forms.length+' [0].name='+forms[0].name);
    var i = 0, form, j;
    while(form = forms[i++]) {
      if(form == myForm) {
        myForm.next = forms[i] ? forms[i] : forms[0];
        myForm.prev = (i-2 >= 0) ? forms[i-2] : forms[forms.length-1];
      }
    }
  }
  
  
  function extendElement(obj) {
    
    obj.isInRange = function() {
      var pos = $(this).position(true);
      return (pos.top < ($(document).height() - 20) && pos.left < ($(document).width() - 20)); 
    };
    
    // .tabFocussed:  select() should be triggered only by tab key, not by clicking into a field.
    
    obj.focusIfInRange = function() {
      if(!this.isInRange()) return;
      this.tabFocussed = true;
      try{  this.focus();  } catch(e) { console.log(e.message || e.description) }
      this.tabFocussed = false;
      // console.log('focus:"'+this.name+'" prev:"'+this.prev.name+'" next:"'+this.next.name+'"');
    };
    
    
    obj.onfocus = function() {
      if(typeof this.select == 'function' && this.tabFocussed)
        this.select();
    };
    
    obj.setRadio = function(value) {
      var radios = this.form[this.name];
      for(var i = 0; i < radios.length; i++) {
        if(radios[i].value === value)
          radios[i].checked = true;
      }
    };
    
    if(typeof(obj.onkeydown) != 'function') {
      obj.onkeydown = function(event) { return controlTab(event, this); };
    }
    
    if(typeof(obj.onload) == 'function')
      obj.onload();
  }
  
  
  
   //   * callback function controllTab
   //   * using the Tabbar will only affect elements in the current Window
  
  function controlTab(evt, obj) {
    /*
     console.log('controlTab  prev:'+obj.prev.form.name+'.'+obj.prev.name+
                              ' this:'+obj.form.name+'.'+obj.name+
                              ' next:'+obj.next.form.name+'.'+obj.next.name);
   */
   
    evt = evt ? evt : event;
    var charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode : 0);
    switch (charCode) {
      case 9: // tab
       if(sys.keys.shiftDown()) {
         obj.prev.focusIfInRange();
       } else {
        // console.log('controlTab: too:'+(typeof obj)+' obj:"'+obj.name+'-'+obj.type+'-'+obj.tagName+'" next:"'+(obj.next && obj.next.name)+'"');
         obj.next.focusIfInRange();
       }
       return false;
    }
  }
  
};


SWO.SYS.ServerPushPop = function(){
    
    var self = this,
        enabled = false,
        mode    = 1;
        
        
    self.init = function(){
      if(!enabled) return false;
      
      switch(mode) {
        case 1: // pop
          Stream.request('http://www.heinelt.de/modules/CMS/CMS_pushpop.php');
          break;
        default: // push
          setInterval(function(){
            Loader.request('http://www.heinelt.de/modules/CMS/CMS_pushpop.php?', {noWinId:true});
          }, 1500);
      }
    };
    
};

SWO.SYS.Format = function() {
  
  this.number_format = function(num, decimal, dec_point, thousend_sep) {
    
    dec_point    = (typeof dec_point    != 'undefined' ? dec_point    : '.');
    thousend_sep = (typeof thousend_sep != 'undefined' ? thousend_sep : ',');
    decimal      = (typeof decimal      != 'undefined' ? decimal      : 0);
    
    var minus = false;
    
    if(typeof num == 'string') {
      var point = num.substr(-3, 1);
      if(point == ',') {
        num = num.split(',');
        var th = num[0].split('.');
        num = th.join('') +'.'+ num[1];
      }
      num = parseFloat(num);
    } else {
      if(num < 0) {
        num = num * (-1);
        minus = true;
      }
    }
    
    num = num.toFixed(decimal);
    num = num.toString();
    
    var num = num.split('.');
    
    var nlength = num[0].length;
    var i = 0;
    var thousend = Array();
    
    while(Math.round(nlength / 3) >= 0) {
      nlength -= 3;
      
      if(nlength >= 0) {
        thousend[i] = num[0].substr(nlength, 3);
        i++;
      } else if(nlength > -3) {
        thousend[i] = num[0].substr(0, (3 + nlength));
      }
    }
    
    thousend = thousend.reverse();
    
    return (minus === true ? '-' : '') + thousend.join(thousend_sep) + (typeof num[1] != 'undefined' ? dec_point + num[1] : '');
    
  };
  
};


/// }}}

// }}}

SWO.SYS._setup();
SWO.TOOLS._setup();


