FotoGarnek = $merge(FotoGarnek, {


    /** nadawanie zdarze� elementowi input FILE kt�ry uploduje plik
     *  automatycznie po wybraniu go z 'przegl�daj' **/
    InputAutoUpload: new Class({
        Implements: Options,
        Binds: ['change'],

        options: {
            form    : '',
            indicator   : 'progress'
        },

        initialize: function(options) {

            this.setOptions(options);

            this.form = $(this.options.form);
            if ( !this.form ) {
                return;
            }
            this.file = this.form.getElement('input[type^=file]');
            if ( !this.file ) {
                return;
            }
            this.indicator = $(this.options.indicator);

            this.initEvents();
        },

        initEvents: function() {

            this.file.addEvent('change', this.change);
        },

        change: function() {
            if ( this.indicator ) {
                this.indicator.show();
            }
            this.form.submit();
        }
    }),

    /** klasa do budowania struktury dokumentu HTML **/
    Builder: new Class({

        buildDomModel: function(parent, data, injectMethod) {
            if ( data["tag"] ) {
                var el = new Element(data.tag);
                for ( var p in data ) {
                    switch(p) {
                        case null,"tag","childs":break;
                        case "id","href","src","rel","value","type","name",
                            "readonly","disabled","frameborder","scrolling","checked",
                            "title","border","framespacing":
                            el.set(p, data[p]);
                            break;
                        case "styles":
                            el.setStyles(data[p]);
                            break;
                        case "html":
                            el.innerHTML = data.html;
                            break;
                        case "events":
                            data[p].each(function(eventName) {
                                el.addEvent(eventName.name, eventName.fn);
                            }.bind(this));
                            break;
                        default:
                            el[p] = data[p];
                            break;
                    }
                }

                switch (injectMethod) {
                    case 'after':
                    case 'before':
                    case 'top':
                    case 'bottom':
                        parent.inject(el, injectMethod);
                        break;
                    default:
                        if ( parent )
                            parent.appendChild(el);
                        break;
                }

                if ( data.childs ) {
                    this.buildDomModel(el, data.childs);
                }
                return el;

            } else if ( typeof data == "object" ) {
                for( var i in data ) {
                    this.buildDomModel(parent, data[i]);
                }
            }
        }
    }),

    /** Klasa do przedstawiania w �adny spos�b informacji typu alert, iframe itp **/
    Box: new Class({
        Implements: [Options, Modalizer, Events],
        Binds: ['_hide', '_key'],

        options: {
            modalOptions: {
                //width       : (window.getScrollSize().x), webkit
                //height      : (window.getScrollSize().y), webkit
                elementsToHide  : 'select, iframe, embed' + (Browser.Engine.trident ? '': ', object'),
                hideOnClick : true,
                updateOnResize  : true,
                layerId     : 'modalOverlay',
                onModalHide : $empty,
                onModalShow : $empty,
                opacity     : 0.1,
                modalStyle:  {
                    display     : 'block',
                    position    : 'fixed',
                    top         : 0,
                    left        : 0,
                    'z-index'   : 2900,
                    'background-color':'#000'
                }
            },
            styles: {
                iframe: {
                    width   : 750,
                    height  : 535,
                    position    : 'absolute',
                    visibility  : 'hidden',
                    margin  : 0,
                    zIndex  : 3000
                },
                info: {
                	width   : 350,
                    height  : 200,
                    position    : 'absolute',
                    visibility  : 'hidden',
                    margin  : 0,
                    padding : 20,
                    zIndex  : 6000
                }
            },
            layout_click    : true,
            show_footer		: true,
            duration : 100
        },

        initialize: function(options) {

            this.setOptions(options);
            this.builder = new FotoGarnek.Builder();

            // webkit fix
            this.options.modalOptions.width = (window.getScrollSize().x);
            this.options.modalOptions.height = (window.getScrollSize().y);

            return this;
        },

        initEvents: function() {
            if ( this.options.layout_click ) {
                this.layer().addEvent('click', this._hide);
            } else {
                this.layer().removeEvents('click');
            }
            document.addEvent('keyup', this._key);
        },

        iframe: function(src, params) {
            this.modalShow( this.options.modalOptions );
            this.initEvents();

            var pos = {
                width : this.options.styles.iframe.width,
                height : this.options.styles.iframe.height
            };

            pos = $merge(pos, params);

            var iframe =
            {tag: 'div', id: 'lbCenter', styles: $merge(this.options.styles.iframe, pos),
                childs: [
                    {tag: 'div', id: 'lbImage', styles: $merge({}, {display: 'block'}),
                        childs: [
                            {tag: 'iframe', id: 'webPage', src: src, scrolling: 'no',
                                frameBorder: 'none', styles: $merge(pos, {display: 'block', border: 'none', width: pos.width + 20, height: pos.height + 20})}
                        ]
                    }
                ]
            };
            this.content = this.builder.buildDomModel( document.body, iframe );
            this.content.getElement('iframe').
                setProperty('allowTransparency', true).
				setProperty('framespacing', 0).
                setProperty('vspace', 0).
                setProperty('hspace', 0).
                setProperty('vspace', 0);
            this.content.setStyles(this._center());
            return this;
        },

        alert2: function(text) {
            if ( $('lbx_alert') ) return this;
            
            this.modalShow( this.options.modalOptions );
            this.initEvents();

			var defaultText = {
				header	: 'Komunikat',
				body	: '',
				ok		: 'Ok'
			};
			text = $merge(defaultText, text);

            var alert2 =
            {tag: 'div', id: 'lbx_alert', className: 'lbx_unlogged', styles: {position:'absolute',visibility  : 'hidden',zIndex:3000},
                childs: [
                    {tag: 'div', className: 'lbx_container lbx_container_2',
                        childs: [
							{tag: 'a', id: 'exit',
								events: [ 
									{name: 'click', fn: this.close.bind(this)} 
								]
							},
							{tag: 'span', className: 'lbx_header', html: text.header},
                            {tag: 'div', className: 'lbx_content lbx_content_2',
								childs: [/** Wypełniane html-em lub modelem **/]
                            },
							{tag: 'div', className: 'lbx_footer',
								childs: [
								         /** wypełniane poniżej **/
								]
							}
                        ]
                    }
                ]
            };
            
            if ( $type(text.body) == 'object' ) {
                alert2.childs[0].childs[2].childs.push(text.body);
            } else {
                alert2.childs[0].childs[2].childs.push({tag: 'p', html: text.body});
            }
            
            if ( this.options.show_footer ) {
            	alert2.childs[0].childs[3].childs.push(
            			{tag: 'input', type: 'button', value: text.ok, id: 'discard',
            				events: [ 
								{name: 'click', fn: this.close.bind(this)} 
							]
						});
            }

            this.content = this.builder.buildDomModel( document.body, alert2 );
            this.content.setStyles(this._center());

            return this;
        },
        
        alert: function(text) {
            if ( $('lbx_alert') ) return this;
            
            this.modalShow( this.options.modalOptions );
            this.initEvents();

			var defaultText = {
				header	: 'Komunikat',
				body	: '',
				ok		: 'Ok'
			};
			text = $merge(defaultText, text);

            var alert =
            {tag: 'div', id: 'lbx_alert', className: 'lbx_unlogged', styles: {position:'absolute',visibility  : 'hidden',zIndex:3000},
                childs: [
                    {tag: 'div', className: 'lbx_container',
                        childs: [
							{tag: 'a', id: 'exit',
								events: [ 
									{name: 'click', fn: this.close.bind(this)} 
								]
							},
							{tag: 'span', className: 'lbx_header', html: text.header},
                            {tag: 'div', className: 'lbx_content',
								childs: [/** Wypełniane html-em lub modelem **/]
                            },
							{tag: 'div', className: 'lbx_footer',
								childs: [
								         /** wypełniane poniżej **/
								]
							}
                        ]
                    }
                ]
            };
            
            if ( $type(text.body) == 'object' ) {
                alert.childs[0].childs[2].childs.push(text.body);
            } else {
                alert.childs[0].childs[2].childs.push({tag: 'p', html: text.body});
            }
            
            if ( this.options.show_footer ) {
            	alert.childs[0].childs[3].childs.push(
            			{tag: 'input', type: 'button', value: text.ok, id: 'discard',
            				events: [ 
								{name: 'click', fn: this.close.bind(this)} 
							]
						});
            }

            this.content = this.builder.buildDomModel( document.body, alert );
            this.content.setStyles(this._center());

            return this;
        },

        confirm: function(text) {
            if ( $('lbx_unlogged') ) return this;

            this.modalShow( this.options.modalOptions );
            this.initEvents();
			
			var defaultText = {
				header	: 'Komunikat',
				body	: '',
				ok		: 'Ok',
				cancel	: 'Anuluj'
			};
			text = $merge(defaultText, text);

            var confirm =
            {tag: 'div', className: 'lbx_unlogged', id: 'lbx_confirm', styles: {position:'absolute',visibility  : 'hidden',zIndex:3000},
                childs: [
                    {tag: 'div', className: 'lbx_container',
                        childs: [
							{tag: 'a', id: 'exit',
								events: [ 
									{name: 'click', fn: function(){this.fireEvent('confirm', ['cancel'])}.bind(this)} 
								]
							},
							{tag: 'span', className: 'lbx_header', html: text.header},
                            {tag: 'div', className: 'lbx_content',
                                childs: [
                                    {tag: 'p', html: text.body},
                                ]
                            },
							{tag: 'div', className: 'lbx_footer',
								childs: [
									{tag: 'input', type: 'button', value: text.cancel, id: 'discard',
										events: [ 
											{name: 'click', fn: function(){this.fireEvent('confirm', ['cancel'])}.bind(this)} 
										]
									},
									{tag: 'input', type:'submit', value: text.ok, id: 'post',
										events: [ 
											{name: 'click', fn: function(){this.fireEvent('confirm', ['ok'])}.bind(this)} 
										]
									},
								]
							}
                        ]
                    }
                ]
            };

            this.content = this.builder.buildDomModel( document.body, confirm );
            this.content.setStyles(this._center());

            return this;
        },
        
        progress: function(text) {
            if ( $('lbx_progress') ) return this;

        	this.modalShow( this.options.modalOptions );
            this.initEvents();
            this.layer().removeEvents('click');
			
			var defaultText = {
				header	: '\u0141aduje',
				body	: '',
				cancel	: 'Anuluj'
			};
			text = $merge(defaultText, text);

            var progress =
            {tag: 'div', className: 'lbx_progress', id: 'lbx_progress', styles: {position:'absolute',visibility  : 'hidden',zIndex:3000},
                childs: [
                    {tag: 'div', className: 'lbx_container', 
                        childs: [
							{tag: 'a', id: 'exit'},
							{tag: 'span', className: 'lbx_header', html: text.header},
                            {tag: 'div', className: 'lbx_content',
                                childs: [
                                    {tag: 'p', html: text.body},
                                ]
                            },
							{tag: 'div', className: 'lbx_footer',
								childs: [
									{tag: 'input', type: 'button', value: text.cancel, id: 'discard',
										events: [ 
											{name: 'click', fn: function(){this.fireEvent('progress', ['cancel'])}.bind(this)} 
										]
									}
								]
							}
                        ]
                    }
                ]
            };

            this.content = this.builder.buildDomModel( document.body, progress );
            this.content.setStyles(this._center());

            return this;
        },

        custom: function(model) {
            this.modalShow( this.options.modalOptions );
            this.initEvents();

            this.content = this.builder.buildDomModel( document.body, model );
            this.content.setStyles(this._center());

            return this;
        },

        close: function() {
            this.setModalOptions({});
            //this.layer().fireEvent('click');
            this.modalHide(this.modalOptions.hideOnClick);
            this._hide();
            return this;
        },

        _center: function() {
            var pos = {top: 0, left: 0};
            pos.left = (window.getWidth() / 2) - (this.content.getWidth() / 2);
            pos.top = window.getScroll().y + (window.getHeight() / 2) - (this.content.getHeight() / 2);
            return pos;
        },

        _hide: function(event) {
            ['lbCenter', 'lbx_alert', 'lbx_confirm', 'lbx_progress', this.content].each(function(el) {
                if ( $(el) ) $(el).destroy();
            });
        },

        _fxShowComplete: function() {
            if ( this.content ) {
                this.content.setStyle('visibility', '');
            }
        },

        _key: function(event) {
            //console.log('a');
            if ( event.code == 27 ) {
                this.close();
            }
        }
    }),

    Fx: {
        Slide: new Class({
            Implements: Options,
            Binds: ['toggle'],

            options: {
                statusElement   : '',
                onShowText      : '',
                onHideText      : '',
                hideOnStart     : true,
                use_cookie      : false,
                disable_event_on_slideIn: false,
                cookie_name     : '',
                cookie_params   : {
                    duration    : 100
                }
            },

            initialize: function(element, options) {

                if (!$(element)) return;

                this.element = $(element);
                this.setOptions(options);
                this.statusElement = $(this.options.statusElement);

                this.slide = new Fx.Slide(element, options);
                //this.slide.wrapper.setStyle('overflow', 'visible');

                this.initEvents();

                this.element.setStyle('display', 'block');

                if ( this.options.use_cookie ) {
                    //(function() {
                        
                        //console.log( 1 * Cookie.read(this.options.cookie_name) );
                        //console.log( (1 * Cookie.read(this.options.cookie_name)) ? 'hide' : 'show' );
                        this.slide[(1 * Cookie.read(this.options.cookie_name)) ? 'hide' : 'show']();

                    //}.delay(5000, this));
                } else {
                    if ( this.options.hideOnStart ) {
                        this.slide.hide();
                    }
                }
            },

            initEvents: function() {
                this.statusElement.addEvent('click', this.toggle);

                this.slide.addEvent('complete', function(event) {
                    var status = !this.slide.open ? this.options.onHideText : this.options.onShowText;
                    if ( status )
                        this.statusElement.set('html', status);
//                    if ( this.slide.open && Browser.Engines.trident() )
//                        this.slide.wrapper.setStyle('overflow', 'visible');
                }.bind(this));
            },

            toggle: function(event) {
                if ( event )
                    event.stop();
                //if ( this.slide.open && Browser.Engines.trident() )
                //        this.slide.wrapper.setStyle('overflow', 'hidden');
                if ( this.options.disable_event_on_slideIn && this.slide.open ) {
                    return;
                }
                if ( this.options.use_cookie ) {
                    var status = this.slide.wrapper.getStyle(this.slide.layout).toInt() ? 1 : 0;
                    Cookie.write(this.options.cookie_name, status, this.cookie_params);
                }
                this.slide.toggle();
            }
        }),
        
        Pulsate: new Class({
            Extends: Fx.CSS,

            initialize: function(element, options){
                this.element = this.subject = $(element);
                this.parent(options);
                this.pulsate = Math.ceil(this.options.pulsate) * 2;
            },

            set: function(now){
                if (typeof now == 'string') now = this.search(now);
                for (var p in now) this.render(this.element, p, now[p], this.options.unit);
                return this;
            },

            compute: function(from, to, delta){
                var now = {};
                for (var p in from) now[p] = this.parent(from[p], to[p], delta);
                return now;
            },

            start: function(properties){
                if ( !this.check(properties) ) return this;
                if (typeof properties == 'string') properties = this.search(properties);
                var from = {}, to = {};
                for (var p in properties){
                    var parsed = this.prepare(this.element, p, properties[p]);
                    from[p] = parsed.from;
                    to[p] = parsed.to;
                }
                this.onComplete = function() {
                    if ( this.pulsate <= 0 ) {
                        this.pulsate = Math.ceil(this.options.pulsate) * 2;
                        this.fireEvent('complete', this.subject);
                        if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
                        return;
                    }
                    var reverseProp = {};
                    for (var p in properties) {
                        reverseProp[p] = [properties[p][1], properties[p][0]];
                    }
                    this.start(reverseProp);
                };
                this.pulsate --;
                return this.parent(from, to);
            }
        })
    },

    Filter : {

        Base : new Class({
            Implements: Options,

            options: {
                element_event       : 'keyup',
                element_property    : 'value',
                add_event       : true
            },

            initialize: function(element, options) {
                this.element = $(element) ? $(element) : element;
                this.setOptions(options);
                this.initEvents();
            },

            initEvents: function() {
                if ( this.options.add_event && $type(this.element) == 'element' )
                    this.element.addEvent(this.options.element_event, this._filter.bind(this));
            },

            set: function(value) {
                if ( $type(this.element) == 'element' )
                    this.element.set(this.options.element_property, value);
            },

            _filter: function(event) {
                if ( event )
                    this.filter(event.target.get(this.options.element_property));
            }
        })
    },

    Validator : {

        Base : new Class({
            Implements: [Options, Events],

            options: {
                active_element_event: 'click'
            },

            initialize: function(element, activeElement, options) {

                this.setOptions(options);

                this.element = $(element) ? $(element) : element;
                this.activeElement = $(activeElement);

                this.initEvents();
            },

            initEvents: function() {
                if ( this.activeElement )
                    this.activeElement.addEvent(this.options.active_element_event, this.validate.bind(this))
            },

            validate: function(event) {
                this.fireEvent('beforeValid', [this]);
                var value = $type(this.element) == 'element' ? this._getValue() : this.element;
                var valid = this._valid(value);
                if ( valid === true ) {
                    this.fireEvent('valid', [this]);
                } else if ( valid === false ) {
                    this.fireEvent('invalid', [this]);
                }
                return valid;
            },

            _getValue: function() {
                var value;
                switch ( this.element.get('type') ) {
                    case "text":
                    case "radiobutton":
                        value = this.element.get('value');
                        break;
                    case 'checkbox':
                        value = this.element.get('checked');
                        break;
                    default:
                        value = this.element.get('value');
                        break;
                }
                return value;
            }
        }),

        /**
         * Kolekcja walidator�w.
         * @example
         * new FotoGarnek.Validator.Collection({
         *      validator: 'Email', value: 'jaka� warto�� lub element', message: 'warto�� %X% jest z�a', options: 'opcje danego walidatora'
         * });
         **/
        Collection : new Class({

            initialize: function(validators) {
                if ( $type(validators) != 'array' ) return;

                this.validators = validators;
                this.collection = [];
                this.errors = [];

                this.validators.each(function(v) {
                    this.collection.push( new FotoGarnek.Validator[v.validator](v.value, null, v.options) );
                }.bind(this));
            },

            validate: function() {
                this.errors = [];
                var valid = true;
                for ( var i = 0; i < this.collection.length; i++ ) {
                    this.errors.push( this.collection[i].validate() ? 1 : 0 );

                    if ( !this.errors[i] ) {
                        valid = false;
                    }
                    this.validators[i]['valid'] = this.errors[i] ? 1 : 0;
                    if ( this.validators[i]['message'] ) {
                        var value = $(this.validators[i].value) ?
                            $(this.validators[i].value).get('value') : this.validators[i].value;
                        this.validators[i]['message'].replace('%X%', value);
                    }
                }
                return valid;
            }
        })
    }

});

FotoGarnek = $merge(FotoGarnek, {
    Filter : {

        toLowerCase: new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                this.set( value.toLowerCase() );
                return value;
            }
        }),

        toUpperCase: new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                this.set( value.toUpperCase() );
                return value;
            }
        }),

        String : new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                this.set( value.replace(/[^a-z����󶿼]/ig, '') );
                return value;
            }
        }),

        Number : new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                this.set( value.replace(/[^0-9����󶿼]/ig, '') );
                return value;
            }
        }),

        DeletePl : new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                value = value.replace(/\u0105/g, 'a')
                     .replace(/\u0107/g, 'c')
                     .replace(/\u0119/g, 'e')
                     .replace(/\u0142/g, 'l')
                     .replace(/\u0144/g, 'n')
                     .replace(/�/g, 'o')
                     .replace(/\u015b/g, 's')
                     .replace(/\u017c/g, 'z')
                     .replace(/\u017a/g, 'z')
                     .replace(/\u0104/g, 'A')
                     .replace(/\u0106/g, 'C')
                     .replace(/\u0118/g, 'E')
                     .replace(/\u0141/g, 'L')
                     .replace(/\u0143/g, 'N')
                     .replace(/�/g, 'O')
                     .replace(/\u015a/g, 'S')
                     .replace(/\u017b/g, 'Z')
                     .replace(/\u0179/g, 'Z');
                this.set( value );
                return value;
            }
        }),

        StringAndNumber : new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                this.set( value.replace(/[^a-z0-9����󶿼]/ig, '') );
                return value;
            }
        }),

        StringNumberSpace : new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                this.set( value.replace(/[^a-z0-9 ����󶿼]/ig, '') );
                return value;
            }
        }),

        Regex : new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value, pattern, flag) {
                this.set( value.replace(new RegExp(pattern, flag), '') );
                return value;
            }
        }),

        Url : new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                if ( !value.match(/http:\/\//) ) {
                    this.set( 'http://' + value );
                }
                return value;
            }
        }),

        MaxLength : new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                var max = this.options.length || false;
                var length = value.length;
                if ( max ) {
                    if ( length >= max ) {
                        value = value.substr(0, max);
                        this.set(value);
                    }
                }
                return value;
            }
        }),

        Nl2Br : new Class({
            Implements: FotoGarnek.Filter.Base,

            filter: function(value) {
                if ( !value ) {
                    value = $type(this.element) == 'element' ? this.element.get('value') : this.element;
                }
                var pattern = "\n{" + (this.options.max_lines + 1) + ",}";
                value = value.replace(new RegExp(pattern, 'g'), "<br/>".repeat(this.options.max_lines + 1));
                value = value.replace(/\n/g, "<br/>");
                this.set(value);
                return value;
            }
        })
    },

    Validator : {

        StringLength : new Class({
            Implements: FotoGarnek.Validator.Base,

            _valid: function(value) {
                value = String.trim(value);
                return value.length <= this.options.max && value.length >= this.options.min;
            }
        }),

        UrlImage : new Class({
            Implements: FotoGarnek.Validator.Base,

            _valid: function(value) {
                value = String.trim(value);

                if ( this.options.maxWidth && this.options.maxHeight ) {
                    var check = function(img) {
                        if ( img.width > this.options.maxWidth ) {
                            this.fireEvent('invalid', [this]);
                            return;
                        }
                        if ( img.height > this.options.maxHeight ) {
                            this.fireEvent('invalid', [this]);
                            return;
                        }
                        this.fireEvent('valid', [this]);
                    }.bind(this);
                    new Asset.image(value, {onload: check/*, onabort: error, onerror: error*/});

                    return null;
                }
                return value.match(/(http:\/\/)?(www\.)?[a-z0-9\.\/\-\_~]+\.(jpg|jpeg|gif|png)$/ig);
            }
        }),
        
        Email : new Class({
        	Implements: FotoGarnek.Validator.Base,
        	
        	_valid: function(value) {
        		value = String.trim(value);
        		var pattern = /^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/;
        		return pattern.test( value );
        	}
        }),
        
        EmailList : new Class({
        	Implements: FotoGarnek.Validator.Base,
        	
        	_valid: function(value) {
        		if ( !value ) return false;
        		var list = value.split(/([\ \,\;])/);
        		for ( var i = 0; i < list.length; i++ )
        		{
        			var EmailValidator = new FotoGarnek.Validator.Email(list[i]);
        			if ( ! EmailValidator.validate() )
        				return false;
        		}
        		return true;
        	}
        }),
        
        NotEmpty : new Class({
        	Implements: FotoGarnek.Validator.Base,
        	
        	_valid: function(value) {
                value = $type(value) == 'string' ? String.trim(value) : value;
        		return ( value.length > 0 || value === true );
        	}
        })
    }
    
});

(function() {
/**
 * Model do odliczania ilości znaków w elementach formularzowych
 * @class FotoGarnek.Countdown
 * @events
 *  - full
 *  - change
 **/
this.Countdown = new Class({
    Implements: [Options, Events],
    Binds: ['count'],

    options: {
        maxLength   : 1000,
        unsigned    : true, // czy wyświetlać tylko dodatnie wartości
        unsigned_class : '',
        format      : '0' // % lub 0
    },

    /**
     * @constructor
     * @param {Element|String} element  - Element obserwowany
     * @param {Element|String} updateElement - Element updatowany
     * @param {Object} options  - Opcje
     **/
    initialize: function(element, updateElement, options) {
        if (!$(element)) return;

        this.element = $(element);
        if ( $type(updateElement) == 'string' ) {
            this.updateElement = $(updateElement);
        }
        this.setOptions(options);
        this.element.addEvent('keypress', this.count);
        this.element.addEvent('keyup', this.count);
    },

    /**
     * Metoda licząca ilość znaków oraz wyświetlająca ilość w elemencie
     * aktualizowanym
     **/
    count: function() {
        var value;
        value = this.element.value.length;

        var rest = this.options.maxLength - value;
        if ( this.options.unsigned ) {
            rest = rest <= 0 ? 0 : rest;
        } else {
            if ( this.options.unsigned_class ) {
                if ( this.updateElement ) {
                    this.updateElement.
                        getParent()[rest <= 0 ? 'addClass' : 'removeClass'](this.options.unsigned_class);
                }
            }
        }

        if ( rest <= 0 ) {
            this.fireEvent('full', [rest]);
        }
        this.fireEvent('change', [rest]);
        if ( this.options.format == '%' ) {
            rest = (rest / this.options.maxLength) * 100;
            this._updateElement(rest.toFixed(1));
        }else{
            this._updateElement(rest);
        }
    },

    _updateElement: function(count) {
        if ( !this.updateElement ) {
            return;
        }
        this.updateElement.set('text', count);
    }
});
}.call(FotoGarnek));
