/*
	Objekt: LED
	
	Version: 1.1
    Datum: 23.01.2012
    * Bug: LED.backgroundColor wurde nicht verwendet

	Version: 1.0
    Datum: 06.11.2011 - 23:11
    * in Objekte aufgeteilt
    * LED.Panel
    * LED.Rect
    * LEDT.Point
    * LED.EventElement
    * LED.Element

   
	Version: 0.5
	Datum: 11:09 22.02.2009
	* Fix: strict Warnungen

	Version: 0.4
	Datum: 16:49 19.02.2009
	* Fix: clear() Funktion

	Version: 0.3
	Datum: 11:21 15.02.2009
	* Funktionen in prototype ausgelagert
	* Parameter von each() geändert
		
    * ----------------------------------------------
    * LED.Panel
    * ----------------------------------------------

    new(height, width, pixel, padding)
        Parameter: 
            height (default:8)
            width (default:8)
            pixel (default:1)
            padding (default:1)
        
	scrollUp(circle)
	scrollDown(circle)
	scrollLeft(circle)
	scrollDown(circle) circle  gibt an, ob "im Kreis" gescrollt werden soll
	
	scrollCol(col, dir) true = up
	scrollRow(row, dir) true = left
	
	copy(LED.Panel)
	
	setByte(col, byte)
	getByte(col)
	
	dots([status])
    
    * erbt
    * ----------------------------------------------
    * LED.Rect
    * ----------------------------------------------
	
    create()    => überschreibt LED.Element.create()
	width(), height(), pixel()
	clear([backgroundcolor] [, color]);
	set(top, left, on/off)
	get(top, left)
	
    * erbt von
    * ----------------------------------------------
    * LED.EventElement
    * ----------------------------------------------
    
    [event] Funktionen
    'click dblclick keydown keyup blur focus change mousedown mouseup mouseout mouseover mousemove'

    * erbt von
    * ----------------------------------------------
    * LED.Element
    * ----------------------------------------------
    
    style()
    color()
    create()
     

*/

Function.prototype.Extend = function(parent){
    function F() {}
    F.prototype = parent.prototype || parent;
    this.prototype = new F();
    this._parent = parent.prototype ? parent : null;
}

LED.resetCSS = 'overflow:hidden;vertical-align: baseline; font-weight: inherit; font-family: inherit; font-style: inherit; font-size: 100%; border: 0; padding: 0; margin: 0;';


/**
 * LED.Element is a generic HTMLElement
 * 
 * style(object)
 * color('#rgb')
 * create(HTMLElement)
 * is(object)
 * */

LED.Element = function(o) {// @param object(style, type, className, id)
    if(!o.type) o.type = 'span';
    
    var element = document.createElement(o.type);

    this.element = function() { return element;};
    
    if(o.resetCSS) element.setAttribute('style', LED.resetCSS); // some kind of a CSS reset
    element.className         = o.className || '';
    element.id                = o.id || '';
    this.style(o.style);
};

LED.Element.Extend({
    create: function(parent) {if(parent) return parent.appendChild(this.element());},
    style: function(o) {
        if(!this.element()) throw new Error('element does not exist!');
        for(var a in o) this.element().style[a] = o[a];
    },
    is: function(obj) {return this.element() === obj;}
});

/**
 * LED.EventElement catch DOM Event
 * 
 * */

LED.EventElement = function(o) {
    LED.EventElement._parent.call(this, o);
    
    var evt_handler = {};
    var element = this.element();
	var _this = this;
    
    /**
     * create eventhandler
     * 
     * first catch some of the DOM Events
     * then add functions for adding the eventfunction
     * */

    'click dblclick keydown keyup blur focus change mousedown mouseup mouseout mouseover mousemove'
    .split(' ')
    .forEach(function(evt) {
		evt_handler[evt] = function() {return false};
        // DOM Event
        element['on' + evt] = function(e){
			e = (e || window.event);
            if(!e.target) e.target = e.srcElement;
            return evt_handler[evt](e);
        };
        // Eventhandler without 'on'
        _this[evt] = function(cb) {
            var old = evt_handler[evt];
            evt_handler[evt] = function(e) {
                old.call(_this, e);
                return cb.call(_this, e);
            };
        };
	} );
};
LED.EventElement.Extend(LED.Element);



/**
 * Ein LED Punkt
 * 
 * */
 
LED.Point = function(o) {
    var 
    color_on = o.color || LED.color,
    color_off = o.backgroundColor || LED.backgroundColor,
    color = color_off,
    style = {
        backgroundColor: color_off,
        top: o.top + 'px',
        left:o.left + 'px',
        width: o.size + 'px',
        height: o.size + 'px',
        position: 'absolute'
    },
    tmp = '', status = false;
    
    this.setColor = function(c, bg) {
        if(c) color_on = c;
        if(bg)color_off = bg;
        
    };
    this.status = function() { return status;};
    this.set = function(set) { 
        status = !!set;
        color = status ? color_on : color_off;
        this.style({backgroundColor: color});
        return status;
    };
    this.flash = function() {
        if(!tmp) {
            tmp = color;
            this.style({backgroundColor: LED.flashBackground}); 
        } else {
            this.style({backgroundColor: tmp}); 
            tmp = '';
        }
    }
    LED.Point._parent.call(this, {type: 'span', style: style, resetCSS: true});
};
LED.Point.Extend(LED.Element);

LED.Point.prototype.toogle = function() {return this.set(!this.status());}
/**
 * LED.Rect 
 * 
 * a rectangle area with LED.Points
 * 
 * The new create area is a DIV.LED
 *
 * Properties:
 * 
 * width
 * height
 * pixel
 * padding
 * 
 * methods
 * 
 * newRect(o)
 * 
 * constructor
 *
 * each(function)
 * clear()
 * set(top, left, status) 
 * get(top, left) 
 * create(parentElement)
 * 
 * */
LED.Rect =  function(o) {
    LED.Rect._parent.call(this, o);
};
LED.Rect.Extend(LED.EventElement);


LED.Panel = function(o) {
    LED.Panel._parent.call(this, {type:'div', className: 'LED'});
    //this.newRect({type:'div', className: 'LED'});

    if(o.width == null || o.width < 1) o.width = 1;
    if(o.height == null || o.height < 1) o.height = 1;
    if(o.pixel == null || o.pixel < 1) o.pixel= 1;
    if(o.padding == null || o.padding < 0) o.padding = 0;

	this.width = function() {return o.width;};
	this.height = function() {return o.height;};
	this.pixel = function() {return o.pixel;};
    
    var bits = [],
    dots = [], 
    panel,
    color = '#F00',
    backcolor = LED.backgroundColor,
    pixel_height = o.pixel + o.padding,
    _this = this;

    for(var i = this.height(); i--;) bits[this.height()-i-1] = Math.pow(2, i);
    
    this.style({
        'position': 'relative',
        width: 1 + (o.width * pixel_height) + 'px',
        height: 1 +  (o.height * pixel_height) + 'px'
    });
    

    // set Bitmask at column
    this.setByte = function(col, c) {
        if(col < 0 || col > this.width()) return;
        
        for(var i = this.height() ; i--;) this.set(i, col, (c & bits[i]));
    };
    // get Bitmask from a column
    this.getByte = function(col) {
        if(col < 0 || col >= this.width()) return null;
        var b = 0;
        for(var i = this.height(); i--;) if(this.get(i, col)) {
            b += bits[i];
        }
        return b;
    };
    
    /**
     * for each dot, callback(dot, row, column)
     * if callback return false iteration stops
     */
	this.each = function(cb) {
		for(var i = dots.length ; i--;) {
            for(var j = dots[i].length ; j--;) {
                if(false == cb(dots[i][j], i, j)) break;
        }}
	};
    
	this.clear = function(c, bg) {
		if(bg) backcolor = bg;
		if(c) color = c;
		this.each(function(d) {d.setColor(color, backcolor); d.set(false);});
	};
    
    this.set = function(t, l, on){
		if(dots[t] && dots[t][l]) dots[t][l].set(on);
	};
    
	this.get = function(t, l){
		return (dots[t] && dots[t][l]) ? dots[t][l].status() : null;
	};
	
    this.click(function(e) { 
        var search;
        var row, col;
        this.each(function(dot, r, c) {
            if(dot.is(e.target)) {
                e.dot = dot;
                e.row = r;
                e.col = c;
                return false;
            }
        }); // each()
    });
    var base_create = this.create;
    
    this.create = function(parent) {
        dots = [];

		for(var i = 0; i < this.height(); ++i) {
			if(!dots[i]) dots[i] = [];
			for(var j = 0; j < this.width(); ++j) {
                var dot = new LED.Point({
                    top:i * pixel_height + o.padding,  
                    left:j * pixel_height + o.padding, 
                    size:o.pixel,
                    color: color, 
                    backgroundColor:backcolor, 
                    parent: this.element()
                });

                dot.create(this.element());
                dot.set(false);
                
                dots[i][j] = dot;
			}
		}

        base_create.call(this, parent);
		return this;
	};
};

LED.Panel.Extend(LED.Rect);


LED.Panel.prototype.copy = function(led) {
    this.each(
        function(dot, t, l){
            led.set(t, l, dot.status());
        }
    );
};
LED.Panel.prototype.scrollLeft = function(circle) {return this.scrollH(true, circle);};
LED.Panel.prototype.scrollRight = function(circle) {return this.scrollH(false, circle);};
LED.Panel.prototype.scrollH = function(dir, circle) {
    var max = dir ? this.width() - 1 : 0;
    var min = dir ? 0 : this.width() - 1;
    
    for(var j = 0; j < this.height(); ++j) {
        var tmp = this.get(j, min);
        this.scrollRow(j, dir);
        this.set(j, max, circle ? tmp : false);
    }
};
LED.Panel.prototype.scrollUp = function(circle) {return this.scrollV(true, circle);};
LED.Panel.prototype.scrollDown = function(circle) {return this.scrollV(false, circle);};
LED.Panel.prototype.scrollV = function(dir, circle) {
    var max = dir ? this.height() - 1 : 0;
    var min = dir ? 0 : this.height() - 1;
    
    for(var j = 0; j < this.width(); ++j) {
        var tmp = this.get(min, j);
        this.scrollCol(j, dir);
        this.set(max, j, circle ? tmp : false);
    }
};
LED.Panel.prototype.scrollCol = function(col, dir) { // dir: true = up
    if(dir) {
        for(var i = 0; i < this.height() - 1; ++i)
        this.set(i, col, this.get(i + 1, col));
    } else {
        var i = this.height();
        while(--i) {
            this.set(i, col, this.get(i - 1, col));
        }
    }
    this.onscroll(col, dir);
};
LED.Panel.prototype.scrollRow = function(row, dir) { // dir: true = left
    if(dir) {
        for(var i = 1; i < this.width(); ++i)  
        this.set(row, i - 1, this.get(row, i));
    } else {
        var i = this.width();
        while(--i) {
            this.set(row, i, this.get(row, i - 1));
        }
    }
    this.onscroll(row, dir);
};
LED.Panel.prototype.dots = function(status) {
    var tmp = [];
    var get_dot = typeof status == 'undefined' ? 
    function(d) {tmp.push(d); } :
    function(d) {if(d.status() == status) tmp.push(d);}
    ;
    this.each(get_dot);
    return tmp;
};
LED.Panel.prototype.onclick=function () {};
LED.Panel.prototype.onscroll= function () {};

