function d(text) {
    $('debug').innerHTML += text + "<br>";
}
function de(text) {
    $('debug').innerHTML = text;
}

var __Dimension = Class.create(
{
    initialize: function (width, height) {
        this.width = width;
        this.height = height;
    },

    getWidth: function () {
        return(this.width);
    },

    getHeight: function () {
        return(this.height);
    },

    toString: function () {
        return("[width=" + this.getWidth() + ",height=" + this.getHeight() + "]");
    }
}
);

var __DesignEntry = Class.create(
{
    initialize: function(design_info_array) {
        this.factor = (design_info_array[5] / 100) * 1;
        this.is_image_set = false;
        if (design_info_array[0] != "XXX") {
            this.is_image_set = true;
            this.position = new _Position(design_info_array[1], design_info_array[2]);
            this.image_dimension = new __Dimension(design_info_array[3], design_info_array[4]);

            var lastSlashIndex = design_info_array[0].lastIndexOf("/");
            this.image_path = design_info_array[0].slice(0, lastSlashIndex + 1);
            this.image_name = design_info_array[0].slice(lastSlashIndex + 1);
        }
        this.color_code = design_info_array[6];
    },
    
    getFactor: function () {
        return(this.factor);
    },

    getPosition: function () {
        return(this.position);
    },

    getOrigImageDimension: function () {
        return(this.image_dimension);
    },

    getColorCode: function () {
        return(this.color_code);
    },

    getImagePathInformation: function () {
        return(this.image_path);
    },

    getImageFilenameInformation: function () {
        return(this.image_name);
    },

    hasImage: function () {
        return(this.is_image_set);
    },

    toString: function () {
        var path_infos = "";
        if (this.hasImage()) {
            path_infos = " imgpath=" + this.getImagePathInformation() + " name=" + this.getImageFilenameInformation() + " Position=" + this.getPosition() + " dimension=" + this.getOrigImageDimension();
        }
        return("color:" + this.getColorCode() + "  factor=" + this.getFactor() + "" + path_infos);
    }
}
);

/**
 * 
 */
var _ImageLoader = Class.create(
{
    initialize: function () {
        this.image_ref = null;
    },
      
    name: function() {
        return("myname")  ;
    },
      
    loadImage: function (caller_ref, current_image, image_url, callback_func) {
        this.caller_ref = caller_ref;
        this.callback = callback_func;
        if (current_image == null)
            this.image_ref = new Image();
        else
            this.image_ref = current_image;
        //$('debug').innerHTML += "URL=" + image_url + "\n<br>";
        // events
        this.loadedBinder = this.imageLoaded.bindAsEventListener(this);
        Event.observe(this.image_ref, 'load', this.loadedBinder);
          
        // set image-src
        this.image_ref.src = image_url;
    },
      
    imageLoaded: function (evt) {
        // remove listener
        Event.stop(evt);
        Event.stopObserving(this.image_ref, 'load', this.loadedBinder);

        //$('debug').innerHTML += "event stopped=" + this.image_ref + "    " + this.loadedBinder;
        this.callback(this.caller_ref, this.image_ref);
        
    }
}
);
 
/**
 * Javascript Slider
 */
var _Slider = Class.create(
{
    /**
     * Create new instance.
     * 
     * @param onChange_callback function to call on value changed.
     * @param initialValue start value.
     * @param min minimum value.
     * @param max maximum value.
     * @param step 
     * @param slider_ref
     * @param slider_image_ref
     */
    initialize: function (onChange_callback, initialValue, min, max, step, slider_ref, slider_image_ref) {
        this.numberRegEx = /[+|-]*[0-9]+/;
        this.min = min;
        this.max = max;
        this.step = step;
          
        this.current = initialValue;
        this.callback = onChange_callback;
          
        this.slider_ref = slider_ref;
        this.slider_image_ref = slider_image_ref;
          
        this.dragging = false;
        this.lastPos = new _Position(0,0);
          
        Event.observe(this.slider_ref, 'mousemove', this.moving.bindAsEventListener(this));
        Event.observe(this.slider_ref, 'mousedown', this.down.bindAsEventListener(this));
        Event.observe(this.slider_ref, 'mouseup',   this.up.bindAsEventListener(this));
        Event.observe(this.slider_ref, 'click',     this.clicked.bindAsEventListener(this));

        Event.observe(this.slider_image_ref, 'click',    this.clicked.bindAsEventListener(this));
        Event.observe(this.slider_image_ref, 'mousemove', this.moving.bindAsEventListener(this));
        Event.observe(this.slider_image_ref, 'mousedown', this.down.bindAsEventListener(this));
        Event.observe(this.slider_image_ref, 'mouseup',   this.up.bindAsEventListener(this));

        this.setValue(this.current, true);
    },
      
    clicked: function (evt) {
        this.dragging = false;
        var x = Event.pointerX(evt);
        var test = Element.cumulativeOffset(this.slider_ref);
        x = x - test.left;
        this.setPos(x);        
        Event.stop(evt);
    },
      
    up: function (evt) {
        this.dragging = false;
        Event.stop(evt);
    },
      
    down: function (evt) {
        this.dragging = true;
        Event.stop(evt);
    },
      
    moving: function (evt) {
        if (this.dragging) {
            var x = Event.pointerX(evt);
            var test = Element.cumulativeOffset(this.slider_ref);
            
            x = x - test.left;
            this.setPos(x);
        }
        Event.stop(evt); 
    },
      
    setPos: function (pos_x) {
        var new_value = this.xToValue(pos_x);
        this.setValue(new_value, false);
    },
      
    setValue: function (value, break_dragging) {
        if ( (value >= this.min) && (value <= this.max) ) {
            this.current = value;
            var x = this.valueToX(value) * 1;
            this.slider_image_ref.style.left = x + "px";
            if (!break_dragging) this.fireChangeEvent(value);
        }
        if (break_dragging) this.dragging = false;
    },
    
    decrease: function (offset) {
        offset = (offset < 0 ? offset * -1 : offset);        
        if (this.current > this.min) {
            this.current -= offset;    
            this.current = (this.current < this.min ? this.min : this.current);
        }
        this.setValue(this.current, true);
        this.fireChangeEvent(this.current);
        
    },
    
    increase: function (offset) {
        offset = (offset < 0 ? offset * -1 : offset);
        if (this.current + offset < this.max) {
            this.current += offset;
            this.current = (this.current > this.max ? this.max : this.current);
        } else {
            this.current = this.max;
        }
        this.setValue(this.current, true);
        this.fireChangeEvent(this.current);
        
    },
      
    fireChangeEvent: function (value) {
        if (this.callback != null) {
            this.callback(value);
        }
    },

    /**
     * @param x the x-position relative to the slider-background.
     */
    xToValue: function (x) {
        var value = 0;

        x -= 13; // width of left-arrow

        var max_w = this.slider_ref.getWidth();
        var width_of_slider_button = this.slider_image_ref.getWidth();
        max_w -= width_of_slider_button;

        var discrete_values = (this.max + width_of_slider_button) - this.min;
        var values_per_pixel = max_w / discrete_values;

        value = Math.round(x / values_per_pixel);

        return(value);
    },
      
    valueToX: function (value) {
        var x = 0;
        var max_w = this.slider_ref.getWidth();
        var width_of_slider_button = this.slider_image_ref.getWidth();
        max_w -= width_of_slider_button;
        var discrete_values = (this.max + width_of_slider_button) - this.min;
        var values_per_pixel = max_w / discrete_values;
        var computed_value = Math.round(value * values_per_pixel);
        x = computed_value + 13; // width of left arrow-image
        return(x);
    },

    html: function () {
        var html = '';
        return(html);
    }
}
);

/**
 * _Position 
 * 
 * Defines a Position x,y
 */
var _Position = Class.create(
{
    /**
     * @param x
     * @param y
     */
    initialize: function(x,y) {
        this.x = x * 1;
        this.y = y * 1;
    },
      
    move: function (dx, dy) {
        this.x = (this.x * 1) + (dx * 1);
        this.y = (this.y * 1) + (dy * 1);
    }, 
      
    toString: function() {
        return("[x=" + this.x + ", y=" + this.y + "]");
    }, 
      
    delta: function (dPos) {
        var result = this.clone(dPos);
        result.x = this.x - dPos.x;
        result.y = this.y - dPos.y;
        return(result);
    },
      
    clone: function (input) {
        var result = new _Position(input.x, input.y);
        return(result);
    },

    getX: function (){
        return(this.x);
    },

    getY: function() {
        return(this.y);
    }
}
);

/**
 * Class _Viewport
 * 
 * Defines a rectangle (left,top, width, height).
 */
var _Viewport = Class.create(
{
    /**
     * Create instance
     * 
     * @param left
     * @param top
     * @param width
     * @param height
     */
    initialize: function(left, top, width, height) {
        this.left = left;
        this.top = top;
        this.width = width;
        this.height = height;
    },

    scale: function(factor) {
        this.left = this.left * factor;
        this.top = this.top * factor;

        this.width = this.width * factor;
        this.height = this.height * factor;
    },
      
    /**
     * Is the point within the viewport?
     * 
     * @param point the _Position instance.
     */
    contains: function (point) {
        var result = true;
        if (point.x < this.left || point.x > (this.left + this.width) ) result = false;
        if (point.y < this.top || point.y > (this.top + this.height) ) result = false;
          
        return(result);
    },

    setDimension: function (left, top, right, bottom) {
        this.left = left;
        this.top = top;
        this.width = right;
        this.height = bottom;
    },

    /**
     * Clone this instance.
     */
    clone: function() {
        var buffer = new _Viewport(this.left, this.top, this.width, this.height);

        return(buffer);
    }
}
);

/**
 * Class _Mask
 */
var _Mask = Class.create( 
{
    /**
     * Create instance.
     * 
     * @param mask_image_ref
     * @param viewport the viewport (left,top, width, height)
     */
    initialize: function (mask_image_ref, viewport) {
        this.image = mask_image_ref;
        this.mask_width = this.image.width;
        this.mask_height = this.image.height;

        this.viewport = viewport;
    },
    
    _getViewportDimension: function () {
        var width = this.viewport.width - this.viewport.left;
        var height = this.viewport.height - this.viewport.top;
        
        var dimension_ar = new Array(2);
        dimension_ar[0] = width;
        dimension_ar[1] = height;
        
        return(dimension_ar);
    },

    setViewport: function (left, top, right, bottom) {
        this.viewport.setDimension(left, top, right, bottom);
    },

    /**
     * Clone this mask
     */
    clone: function () {
        var buffer_image = new Image();
        buffer_image.src = this.image.src;
        
        var buffer = new _Mask(buffer_image, this.viewport.clone());
        buffer.mask_width = this.image.width;
        buffer.mask_height = this.image.height;

        buffer_image.src = this.image.src;

        buffer_image.width = this.image.width;
        buffer_image.height = this.image.height;
        buffer_image.style.width = this.image.style.width.match(this.numberRegEx);
        buffer_image.style.height = this.image.style.height.match(this.numberRegEx);

        return(buffer);
    },

    /**
     * Scale mask-image by factor.
     */
    scale: function (f) {
        var w = Math.round(this.mask_width * f);
        var h = Math.round(this.mask_height * f);

        this.image.style.width = w + "px";
        this.image.style.height = h + "px";
        this.image.width = w;
        this.image.height = h;

        this.mask_width = w;
        this.mask_height = h;
    }
}
);

/**
 * Class _Editor
 * 
 * Functions for a single editor. (one site of the case)
 */
var _Editor = Class.create(
{
    /**
     * Create new instance.
     * 
     * @param name the name for this editor.
     * @param width the width of the editor
     * @param height the height of the editor
     * 
     * @param destination_w_inch the full width in inch
     * @param destination_h_inch the full height in inch
     * @param withEvents true => register events; false else.
     *
     * @param mask_img_path
     * @param helper_mask_img_path
     * @param after_mask_loaded_listener
     * @param viewport 
     */
    initialize: function(name, width, height, destination_w_inch, destination_h_inch, withEvents, mask_img_path, helper_mask_img_path, after_mask_loaded_listener, viewport) {
        this.numberRegEx = /[+|-]*[0-9]+/;
        this.defaultBackgroundColor = '#BBBBBB';
        this.active_border = '2px solid white'; //'2px solid #4FA600'; //#948E8E';
        this.inactive_border = '2px solid white';

        // mask setup parameter
        this.mask_img_path = mask_img_path;
        this.helper_mask_img_path = helper_mask_img_path;
        this.after_mask_loaded_listener = after_mask_loaded_listener;
        this.mask_viewport = viewport;

        this.setEditorsName(name);

        // html representation
        this.div = new Element("div", {
            "name": this.name,
            "id": this.name
        });
        this.div.setStyle({
            "position": "relative",
            "backgroundColor": this.defaultBackgroundColor,
            "textAlign": "center",
            "width": width + "px",
            "height": height + "px",
            "marginLeft": "auto",
            "marginRight": "auto",
            "overflow": "hidden",
            "border": this.inactive_border
        });
        this.div.hide();

        this.designer = null;
        this.image = null;
        this.helper_image_ref = null; // background-image (only if no color!)

        this.filename = ""; // this.setFilename("");
        this.width = width; this.height = height; // this.setEditorSize(width, height);
        this.factor = 1; //         this.setScaleFactor(1);
        this.setBackgroundColor("");

        //
        this.orig_w = 0;
        this.orig_h = 0;

        // position of image within the editor
        this.left = 0;
        this.top  = 0;

        // destination width and height for real-laptop/workstation
        this.destination_w = destination_w_inch;
        this.destination_h = destination_h_inch;
          
        // for resize and moving
        this.dragging = false;
        this.resizing = false;
          
        // register events
        this.withEvents = withEvents;
        if (withEvents)
            this.registerEditorEvents();

        // min / max procent
        this.min_scale = 10;
        this.max_scale = 200;

        // load mask
        if (this.after_mask_loaded_listener != null) this.__setup_masks();
    //d("Editor initialized " + this.getName());
    },

    toString: function () {
        return("_Editor ["+this.getName() + "]");
    },


    __updateEditorValues: function (design_entry) {
        try {
            this.changeBackgroundColor(design_entry.getColorCode());
            this.factor = design_entry.getFactor();

            if (design_entry.hasImage()) {
                var pos = design_entry.getPosition();
                this.left = pos.getX();
                this.top = pos.getY();

                var dim = design_entry.getOrigImageDimension();
                this.orig_w = dim.getWidth();
                this.orig_h = dim.getHeight();

                this.changeImage(design_entry.getImagePathInformation(), design_entry.getImageFilenameInformation());
            }
        } catch (e) {
            d("_Editor::__updateEditorValues " + e);
        }
    },

    setMaskLoadedListener: function (listener) {
        this.after_mask_loaded_listener = listener;
    },

    __setup_masks: function () {
        var loader1 = new _ImageLoader();
        var loader1_helper = new _ImageLoader();

        loader1.loadImage(this, null, this.mask_img_path, function(self, image) {
            self.setMask(new _Mask(image, self.mask_viewport));

            // load and append helper image
            if (self.helper_mask_img_path != null) {
                loader1_helper.loadImage(self, null, self.helper_mask_img_path, function(self, image) {
                    self.setHelperMask(image);
                    self.after_mask_loaded_listener();
                });
            } else {
                self.after_mask_loaded_listener();
            }
        });
    },

    setEditorsName: function (newName) {
        this.name = newName;
    },

    setEditorSize: function (width, height) {
        this.width = width;
        this.height = height;

        // resize div-container
        this.div.setStyle({
            "width": width + "px",
            "height": height + "px"
        });
    },

    /**
     * getEditorsDimension
     *
     * @return __Dimension the editors width and height
     */
    getEditorsDimension: function () {
        return(new __Dimension(this.width, this.height));
    },

    /**
     * Copy attributes from given editor_reference to local copy.
     */
    clone: function () {
        var dimension = this.getEditorsDimension();
        var clone = new _Editor(this.getName()+"_clone", dimension.getWidth(), dimension.getHeight(), 0, 0, true);

        this._updateClone(clone);

        return(clone);
    },

    _updateClone: function (ref) {
        if (this.mask_ref.image) {
            var mask = this.getMask().clone();
            ref.setMask(mask);

            var helper_mask = this.cloneHelperMask();
            ref.setHelperMask(helper_mask);

        //            ref.mask_ref.src = this.mask_ref.image.src;
        //            ref.mask_ref.image.style.zIndex = this.mask_ref.image.style.zIndex;
        //            ref.mask_ref.image.setAttribute("name", "mask_" + this.getName());
        //            ref.mask_ref.image.style.left = '0px';
        //            ref.mask_ref.image.style.top  = '0px';
        //            ref.mask_ref.image.style.position = 'absolute';
        //
        //            ref.div.style.width = this.mask_ref.image.width;
        //            ref.div.style.height = this.mask_ref.image.height;

        //            ref.div.appendChild(ref.mask_ref.image);
        }
    },

    registerEditorEvents: function () {
        //this.click_binder = this.editor_clicked.bindAsEventListener(this);
        this.down_binder  = this.editor_mousedown.bindAsEventListener(this);
        this.up_binder    = this.editor_mouseup.bindAsEventListener(this);
        this.move_binder  = this.editor_mousemove.bindAsEventListener(this);
        //this.mouseout_binder = this.img_mouse_out.bindAsEventListener(this);

        //Event.observe(this.div, 'click', this.click_binder);
        Event.observe(this.div, 'mousedown', this.down_binder);
        Event.observe(document, 'mouseup',   this.up_binder);
        Event.observe(document, 'mousemove', this.move_binder);
    },
    
    img_mouse_out: function (evt) {
        if (this.image != null) {
            this.image.style.border = '0px';
            this.image.style.margin = '1px';
        }  
    },
    
    img_mouse_in: function (evt) {
        if (this.image != null) {
            this.image.style.border = '1px dashed #FFFFFF';
            this.image.style.margin = '0px';
        }
    },
    
    unregisterEditorEvents: function () {
        Event.stopObserving(this.div, 'mousedown', this.down_binder);
        Event.stopObserving(document, 'mouseup',   this.up_binder);
        Event.stopObserving(document, 'mousemove', this.move_binder);
    },

    // TODO: check function: if (false) ????
    editor_mousedown: function (evt) {
        if (this.image == null) return;

        this.dragging = true;
        //var x = Event.pointerX(evt);
        if (false) {
            var test = Element.cumulativeOffset(this.div);
            // translate to editors-coordinations
            x = x - test.left;         
            var y = Event.pointerY(evt);
            // translate to editors-coordinations
            y = y - test.top;
            this.last_mouse_point = new _Position(x, y);        
        //this.lastScrolled = new Date();
        }
        
        Event.stop(evt);
    },
      
    editor_mouseup: function (evt) {
        this.dragging = false;
        this.resizing = false;
        if (this.image == null) return;
        this.img_mouse_out(evt);
        Event.stop(evt);
    },
      
    editor_clicked: function (evt) {
        if (this.designer) {
            this.designer.unregisterMouseEvents();
        }
        
        // Events...
        this.registerEditorEvents();
        
        // set as active editor
        if (this.designer != null) this.designer.setActiveEditor(this);
        this.dragging = false;
        this.img_mouse_in(evt);
    },
      
    editor_mousemove: function (evt) {
        if (this.image == null) return;
          
        this.div.style.cursor = 'auto';
        // move , se-resize, auto
         
        // mouse position on page
        var x = Event.pointerX(evt);
        var test = Element.cumulativeOffset(this.div);
        // translate to editors-coordinations
        x = x - test.left;         
        var y = Event.pointerY(evt);
        // translate to editors-coordinations
        y = y - test.top;
        var pos_in_editor = new _Position(x, y);
        var pos_in_viewport = null;
        // translate to viewports coordinations
        pos_in_viewport = this.translateToViewportCoord(pos_in_editor);
         
        var left = this.image.style.left.match(this.numberRegEx) * 1;
        var top  = this.image.style.top.match(this.numberRegEx)  * 1;
        var width = this.image.style.width.match(this.numberRegEx)  * 1;
        var height = this.image.style.height.match(this.numberRegEx)  * 1;
         
        // default event-handling
        var viewport_pos = new _Position(left, top);
        viewport_pos = this.translateToViewportCoord(viewport_pos);
         
        var viewport = new _Viewport(viewport_pos.x, viewport_pos.y, width, height);
        //this.last_mouse_point diff pos_in_editor
        if (this.last_mouse_point == null) this.last_mouse_point = pos_in_editor;
        var diff = pos_in_editor.delta(this.last_mouse_point);
        this.last_mouse_point = pos_in_editor;
         
        // set cursor for resizing, or moving mode!
        var resize = false;
        if (x < (left + width) + 5 && x > (left + width) -5 ) resize = true;
        if (!resize) {
            if (y < (top + height) + 5 && y > (top + height) -5 ) resize = true;
        }
        if (this.resizing) resize = true;
         
        var contains = viewport.contains(pos_in_viewport);
        if (contains) { 
            this.div.style.cursor = 'move';
            this.img_mouse_in(evt);
        } else {
            if (!this.resizing && !this.dragging) {
                this.img_mouse_out(evt);
            } else{                
                this.img_mouse_in(evt);
            }
        }
        if (resize) {
            this.div.style.cursor = 'se-resize';
            this.img_mouse_in(evt);
        }

        if (!resize && this.dragging) {
            this.moveByOffset(diff.x, diff.y);
        } else if (resize && this.dragging) {
            this.resizing = true;

            var w = this.image.style.width.match(this.numberRegEx)* 1.0;
            var h = this.image.style.height.match(this.numberRegEx)* 1.0;            
            
            var new_w = w + diff.x;
            var p = new_w / this.orig_w;
            p = p * 100;
            p = Math.round(p, 0);

            this.scaleImage(p);
            slider.setValue(p, false);
        }
         
        Event.stop(evt);
    },
      
    registerDesigner: function (designer_ref) {
        this.designer = designer_ref;
    },

    /**
     *
     */
    setBackgroundColor: function (colorCode) {
        this.backgroundColor = colorCode;
    },

    getBackgroundColor: function () {
        return(this.backgroundColor);
    },
      
    /**
     * 
     */
    changeBackgroundColor: function (color_code) {
        this.setBackgroundColor(color_code);
        try {
            // is there an background-image?
            if (this.helper_image_ref != null) {
                // if no backgroundcolor available --> set background helper-image; else hide it
                if (this.getBackgroundColor() == "") {
                    this.helper_image_ref.show();
                } else {
                    this.helper_image_ref.hide();
                }
            } else if (this.getBackgroundColor() == "") { // no background-image
                //d("ChangeColor: " + this.getName() + "  designer=" + this.designer.editor_type);
                if (this.designer.editor_type == "workstation") {
                    this.setBackgroundColor(this.defaultBackgroundColor);
                }
            }

            if (this.getBackgroundColor() != "") {
                this.div.style.backgroundColor = this.getBackgroundColor();
            }

        } catch (e) {
            d("ChangeBackgroundError=" + e);
        }
    },
      
    /**
     * Return the editor`s name.
     * 
     * @return the editorname
     */
    getName: function () {
        return(this.name);
    },
      
    /**
     * Set the editor mask.
     * 
     * @param mask the editor`s mask
     */
    setMask: function (mask) {
        this.mask_ref = mask;
        this.mask_ref.image.style.zIndex = 100;
        this.mask_ref.image.setAttribute("name", "mask_" + this.getName());
        this.mask_ref.image.style.left = '0px';
        this.mask_ref.image.style.top  = '0px';
        this.mask_ref.image.style.position = 'absolute';

        this.div.style.width = this.mask_ref.image.width;
        this.div.style.height = this.mask_ref.image.height;

        this.div.appendChild(this.mask_ref.image);          
    },

    getMask: function () {
        return(this.mask_ref);
    },

    changeMask: function (mask) {
        this.div.removeChild(this.mask_ref.image);
        this.setMask(mask);
    },

    cloneMask: function () {
        return(this.mask_ref.clone());
    },

    scaleMask: function (scaleFactor) {
        if (this.mask_ref) {
            var w = this.mask_ref.image.width * scaleFactor;
            var h = this.mask_ref.image.height * scaleFactor;

            this.mask_ref.image.width = w;
            this.mask_ref.image.height = h;
        }
    },

    scaleHelperMask: function (scaleFactor) {
        if (this.helper_image_ref) {
            var w = this.helper_image_ref.width * scaleFactor;
            var h = this.helper_image_ref.height * scaleFactor;

            this.helper_image_ref.style.width = w + "px";
            this.helper_image_ref.style.height = h + "px";
        }
    },

    /**
     * Scale editors width and heights.
     * TODO: scale
     */
    scaleEditor: function (scaleFactor) {
        this.setScaleFactor(this.getScaleFactor() * scaleFactor);

        // scale editors html representation
        var dimension = this.getEditorsDimension();
        this.setEditorSize(dimension.getWidth() * scaleFactor, dimension.getHeight() * scaleFactor);

        // scale editors mask and helper image
        this.scaleMask(scaleFactor);
        this.scaleHelperMask(scaleFactor);

        // scale viewport
        this.mask_viewport.scale(scaleFactor);

        var pos = new _Position(this.left, this.top);
        this.left = Math.ceil(this.left * scaleFactor);
        this.top =  Math.ceil(this.top * scaleFactor);
        this.moveImage(this.left, this.top);

        // scale user-image
        this._scaleUserImage(this.getScaleFactor());
    },

    _scaleUserImage: function (scaleFactor) {
        try {
            if (this.image) {
                var w = Math.round(this.orig_w * scaleFactor);
                var h = Math.round(this.orig_h * scaleFactor);
                //d("w=" + w + "   h=" + h);
                this.image.style.width  = w + 'px';
                this.image.style.height = h + 'px';
            }
        } catch (e) {
            d("err:" + e);
        }
    },

    /**
     * Scale image position.
     */
    scalePosition: function (scaleFactor) {
        if (this.image) {
            this.left = this.left * scaleFactor;
            this.top = this.top * scaleFactor;
        }
    },
    
    setScaleFactor: function (newScaleValue) {
        this.factor = newScaleValue;
    },

    getScaleFactor: function () {
        return(this.factor);
    },

    /**
     * 
     */
    setHelperMask: function (helper_image_ref) {
        this.helper_image_ref = helper_image_ref;
        this.helper_w = helper_image_ref.width;
        this.helper_h = helper_image_ref.height;
        
        this.helper_image_ref.style.zIndex = 0;
        this.helper_image_ref.style.position = 'absolute';
        this.helper_image_ref.style.left = '0px';
        this.helper_image_ref.style.top  = '0px';

        this.helper_image_ref.style.width = this.helper_w + "px";
        this.helper_image_ref.style.height = this.helper_h + "px";

        this.div.appendChild(this.helper_image_ref);
    },

    cloneHelperMask: function () {
        var helper_mask = new Image();
        helper_mask.style.zIndex = 0;
        helper_mask.style.position = 'absolute';
        helper_mask.style.left = '0px';
        helper_mask.style.top  = '0px';

        helper_mask.style.width = this.helper_w + "px";
        helper_mask.style.height = this.helper_h + "px";

        return(helper_mask);
    },

    removeHelperMask: function () {
        if (this.helper_image_ref != null) {
            this.helper_image_ref.style.display = 'none';
            this.div.removeChild(this.helper_image_ref);
            this.helper_image_ref = null;
        }
    },

    /**
     * Returns the width and height of the viewport.
     *
     * @return an associative array ('width', 'height').
     */
    getViewportDimension: function() {
        return(this.mask_ref._getViewportDimension());  
    },

    /**
     * only for preview function.
     */
    changeViewport: function (left, top, right, bottom) {
        this.mask_ref.setViewport(left, top, right, bottom);
    },
      
    /**
     * Set the editors image.
     * 
     * @param image_ref the image reference
     */
    _setImage: function (image_ref) {
        this.image = image_ref;
        if ($(editor_image_id)) {

        } else {
            this.div.appendChild(this.image);
        }
          
        this.image.style.zIndex = 5;
        this.image.style.position = 'absolute';
        this.image.style.left = 0 + 'px';
        this.image.style.top  = 0 + 'px';
        this.image.style.width = '';
        this.image.style.height = ''; 
        var editor_image_id = "image_" + this.getName();
        this.image.setAttribute("id", editor_image_id);
          
        this.moveImage(0, 0);
    },
      
    addImage: function (filename, path, width, height, swidth, sheight) {
        if (dlg != null) dlg.close();

        this.changeBackgroundColor("");

        this.orig_w = width;
        this.orig_h = height;
        
        this.orig_ws = swidth;
        this.orig_hs = sheight;
        
        this.left = null;
        this.top = null;
        
        this.setScaleFactor(1);
        this.path = this.__addSlash(path);
        this.changeImage(this.path, filename);
    },
    
    __addSlash: function (path) {
        var len = path.length;
        if (path.charAt(len-1) != "/") {
            path += "/";
        }
        if (path.charAt(0) != "/") {
            path = "/" + path;
        }
        return(path);
    },

    setFilename: function (newFilename) {
        this.filename = newFilename;
    },
    getFilename: function () {
        return(this.filename);
    },

    changeImage: function (path, filename) {
        this.path = path;
        this.setFilename(filename);

        if (this.path == "") {
            if (this.getName() == "front") {
                this.image_url = '/customer_images/normal/small_' + filename;
                this.orig_w = this.orig_ws;
                this.orig_h = this.orig_hs;
            } else {
                this.image_url = '/customer_images/normal/' + filename;
            }
        } else {
            this.image_url = this.path + filename;
        }

        // <--- after image is loaded...
        var _afterLoaded = function (caller_ref, image_ref) {
            if (caller_ref.image == null) {
                caller_ref.image = image_ref;
                caller_ref._setImage(caller_ref.image);
            }
            caller_ref.image.src = caller_ref.image_url;

            caller_ref.image.style.width  = Math.round(caller_ref.orig_w * caller_ref.factor) + 'px';
            caller_ref.image.style.height = Math.round(caller_ref.orig_h * caller_ref.factor) + 'px';
            
            if (caller_ref.left == null || caller_ref.top == null) {
                caller_ref.__centerImage();
            }
            
            caller_ref.moveImage(caller_ref.left, caller_ref.top);
            if (caller_ref.withEvents) {
                caller_ref.designer.fireEditorActivated(caller_ref); // editor has changed
            }
        };
        // --->

        if (this.imageLoader == null) this.imageLoader = new _ImageLoader();
        this.imageLoader.loadImage(this, null, this.image_url, _afterLoaded);
    },
    
    __centerImage: function () {
        var image_w = this.image.style.width.match(this.numberRegEx)* 1.0;
        this.left = Math.round((this.mask_ref.viewport.width / 2) - (image_w / 2), 0);
            
        var image_h = this.image.style.height.match(this.numberRegEx)* 1.0;
        this.top = Math.round((this.mask_ref.viewport.height / 2) - (image_h / 2), 0);
        
        this.moveImage(this.left, this.top);
    },
      
    scaleImage: function (procent_value) {
        if (this.designer.loading) return;

        if (procent_value < this.min_scale) return;
        if (procent_value > this.max_scale) return;
          
        if (this.image != null && $('image_' + this.getName()).complete) {
            this.setScaleFactor(procent_value / 100);
            var w = this.orig_w;
            var h = this.orig_h;
            w = Math.round(w * this.getScaleFactor());
            h = Math.round(h * this.getScaleFactor());
            this.image.style.width = w + 'px';
            this.image.style.height = h + 'px';
        }
    },

    /**
     * Move the image
     * 
     * @param new_left viewport-coordinations
     * @param new_top
     */
    moveImage: function (new_left, new_top) {
        var pos = new _Position(new_left, new_top);

        pos = this.translateToEditorCoord(pos);

        if (this.image != null) {
            this.image.style.left = pos.x + 'px';
            this.image.style.top = pos.y + 'px';
        }

        if (this.withEvents)
            this.designer.fireEditorActivated(this);
    },
      
    moveByOffset: function (left_offset, top_offset) {
        if (this.image != null) {
            var pos = new _Position(
                this.image.style.left.match(this.numberRegEx) * 1,
                this.image.style.top.match(this.numberRegEx) * 1
                );
            pos.move(left_offset, top_offset);
          
            this.image.style.left = pos.x + 'px';
            this.image.style.top  = pos.y + 'px';
          
            this.designer.fireEditorActivated(this);
        }
    },
      
    /**
     * Translate a position from editor-coordinates to viewport-coordinates.
     */
    translateToViewportCoord: function (editor_position) {
        var left_mask = this.mask_ref.image.style.left.match(this.numberRegEx) * 1;
        var top_mask  = this.mask_ref.image.style.top.match(this.numberRegEx) * 1;
          
        var viewport_left = this.numberRegEx.exec(this.mask_ref.viewport.left);
        var viewport_top  = this.numberRegEx.exec(this.mask_ref.viewport.top);
          
        editor_position.move(
            - left_mask - viewport_left,
            - top_mask  - viewport_top
            );
        return(editor_position);
    },
      
    /**
     * Translate a position from viewport-coordinates to editor-coordinates.
     */
    translateToEditorCoord: function (viewport_position) {
        var left_mask = this.mask_ref.image.style.left.match(this.numberRegEx) * 1;
        var top_mask  = this.mask_ref.image.style.top.match(this.numberRegEx)  * 1;
        var viewport_left = this.mask_ref.viewport.left;
        var viewport_top  = this.mask_ref.viewport.top;

        viewport_position.move(
            left_mask + viewport_left,
            top_mask  + viewport_top
            );
        return(viewport_position);
    },
      
    getConfigString: function () {
        var result = "";
        var filename = this.getFilename();
        var left = 0;
        var top = 0;
        var pos = new _Position(0, 0);

        if (filename != "") {
            left = this.image.style.left.match(this.numberRegEx) * 1;
            top  = this.image.style.top.match(this.numberRegEx) * 1;
            pos = new _Position(left, top);
            pos = this.translateToViewportCoord(pos);
        }
        
        var w = this.orig_w;
        var h = this.orig_h;
        var f = Math.round(this.getScaleFactor() * 100);
        var color = this.div.style.backgroundColor = this.backgroundColor;
        
        var destination_w = this.destination_w;
        var destination_h = this.destination_h;

        if (filename == "") filename = "XXX"; // no filename given, but color?!
        var viewport_dim = this.getViewportDimension();
        var viewport_width = viewport_dim[0];
        var viewport_height = viewport_dim[1];

        var full_path = filename;
        if (filename != "XXX") full_path = this.path + filename;
        result = full_path + ":" + pos.x + ":" + pos.y + ":" + w + ":" + h + ":" + f + ":" + color + ":" + destination_w + ":" + destination_h + ":" + viewport_width + ":" + viewport_height;
        result = encodeURI(result);

        return(result);  
    },

    getPositionInViewport: function () {
        if (this.image != null) {
            var left = this.image.style.left.match(this.numberRegEx) * 1;
            var top  = this.image.style.top.match(this.numberRegEx) * 1;
        } else {
            left = 0;
            top = 0;
        }
        var pos = new _Position(left, top);
        pos = this.translateToViewportCoord(pos);

        return(pos);
    },
      
    clear: function () {   
        try {
            this.setFilename("");
            this.orig_w = 0;
            this.orig_h = 0;
            this.setScaleFactor(1);
          
            //            if (this.helper_image_ref != null) this.div.removeChild(this.helper_image_ref);
            //            this.helper_image_ref = null;

            if (this.image != null) this.div.removeChild(this.image);
            this.image = null;
        
            this.changeBackgroundColor("");
        } catch (e) {
            alert("clear-exc=" + e.description);
        }
    },
      
    hideEditor: function () {
        //this.div.style.display = 'none';
        $(this.div).hide();
    },
      
    showEditor: function () {
        //this.div.style.display = 'block';
        var editor_container = $(this.div);
        editor_container.show();
    },
      
    /**
     * Reset Image
     * Image is placed at 0,0 and the scaling factor is set to 1.
     */
    reset: function () {
        this.changeBackgroundColor("");

        this.scaleImage(100);
        this.__centerImage();
    },
      
    /**
     * 
     */
    html: function () {
        return(this.div);
    }
}
);

/**
 * LabelDesigner
 * 
 * The whole desinger function.
 */
var LabelDesigner = Class.create(
{
    /**
     * Initialize the designer
     * 
     */
    initialize: function(designer_type_string) {

        this.editor_type = designer_type_string;

        this.numberRegEx = /[+|-]*[0-9]+/;

        this.designLoadedListenerList = new Array();
        Element.extend(this.designLoadedListenerList);

        this.previewEditor = null;
        this.previewEditorBig = null;
        this.previewbox_initialized = false;

        this.chooser_div = null;
        
        // create array for editor references
        this.editors_ar = new Array();
        this.complete = false;
        this.loading = false; // while restoring from database
        this.isStored = false; // indicates wether the storage was successfully or not

        // no active editor this time
        this.active_editor = null;
        this.infobox = null;
      
        // no store-id this time
        this.store_id = 0;
        this.use_gallery = 0; // DON`T USE GALLERY IMAGE
        this.gallery_image = '';
      
        this.editorActivatedListener = new Array();
      
        // register button-action to store configuration
        var cart_quantity = $('cart_quantity');
        var self = this;
        if (cart_quantity) {
            //self.orig_submit = cart_quantity.submit;

            $('cart_quantity').onsubmit = function () {
                self.storeInDatabase();
                return(self.isStored);
            };
        }
    },

    /**
     * Submit the cart.
     */
    _submit_cart: function () {
        var cart_quantity = $('cart_quantity');
        if (cart_quantity) {
            //cart_quantity.submit = this.orig_submit;
            cart_quantity.submit();
        }
    },

    toString: function() {
        return("Designer: " + this.editor_type);
    },

    setEditorType: function (editor_type) {
        this.editor_type = editor_type;
    },

    /**
     * Callback for restoring designs.
     *
     * @param transport
     */
    restore_processResult: function (transport) {
        // this = the designers instance
        //alert("this=" + this);

        var text = "";
        //alert("text:" + transport.responseText);
        if (transport.responseText != "") {
            text = transport.responseText.evalJSON(true);
        } else {
            this.loading = false;
            return;
        }

        var left_info  = "";
        var front_info = "";
        var right_info = "";

        if (text.editor_type) {
            if (text.editor_type != "") this.editor_type = text.editor_type;
        } //else { alert("neu");}

        if ( typeof(text.left)  != 'undefined') left_info  = text.left.split(":");
        if ( typeof(text.front) != 'undefined') front_info = text.front.split(":");
        if ( typeof(text.right) != 'undefined') right_info = text.right.split(":");

        this.store_id = text.store_id * 1;
        //d("design_store_id=" + this.store_id);
        //d("editor_type=" + this.editor_type);
        var design_entry = null;

        //debug_("store_id on load=" + designer.store_id);

        if (left_info.length > 1 && this.getEditorCount() > 0) {
            design_entry = new __DesignEntry(left_info);
            this.__updateEditorValues(0, design_entry);
        }

        if (front_info.length > 1 && this.getEditorCount() > 1) {
            design_entry = new __DesignEntry(front_info);
            this.__updateEditorValues(1, design_entry);
        }

        if (right_info.length > 1 && this.getEditorCount() > 2) {
            design_entry = new __DesignEntry(right_info);
            this.__updateEditorValues(2, design_entry);
        }

        this.setActiveEditor(this.editors_ar[0]);

        this.fireDesignLoaded();
        this.loading = false;
    },
    
    /**
     * Add a new Editor.
     * 
     * @param editor_ref the reference to the editor.
     */
    addEditor: function (editor_ref) {
        editor_ref.registerDesigner(this);
        this.editors_ar.push(editor_ref);
    //d("editor added " + editor_ref.getName());
    },
    
    /**
     * Changes the active editor.
     * 
     * @param editor_name the name for this editor.
     */
    setActiveEditorByName: function (editor_name) {
        var editor = sh_search_ar(
            this.editors_ar,
            function (element) {
                return((element.getName() == editor_name) ? true : false)
            }
            );
        this.setActiveEditor(editor);
    },
    
    /**
     * Set active editor by reference.
     * 
     * @param editor_ref the editor`s reference.
     */
    setActiveEditor: function (editor_ref) {
        // reset border on last active-editor
        if (this.active_editor != null) {
            // set inactive border
            this.active_editor.div.style.border = this.active_editor.inactive_border;
            //this.active_editor.div.style.display = 'none';
            this.active_editor.hideEditor();
        }

        this.active_editor = editor_ref;
        // set border for active editor
        this.active_editor.div.style.border = this.active_editor.active_border;
        //this.active_editor.div.style.display = 'block';
        this.active_editor.showEditor();
        
        this.fireEditorActivated(this.active_editor);
    },
  
    /**
     * Show hidden element step by step. Call callback function if finished.
     * 
     * @param id_name the id of the html-element.
     * @param callback_func function to call after finished.
     */
    showEditor: function (id_name, callback_func) {
        new Effect.BlindDown(id_name, { 
            duration: 10
        });
    },
    
    /**
     * Hide element step by step. Call callback function if finished.
     * 
     * @param id_name the id of the html-element.
     * @param callback_func function to call after finished.
     */
    hideEditor: function (id_name, callback_func) {
        new Effect.Opacity(id_name, 
        {
            duration:2, 
            from:0.0, 
            to: 1.0,
            transition: Effect.Transitions.linear
        });
    },
    
    /**
     * 
     */
    fireEditorActivated: function (the_active_editor_ref) {
        try {
            if (this.loading) return;
            var max_listener = this.editorActivatedListener.length;
            var i = 0;
            for (i=0; i < max_listener; i++) {
                var listener = this.editorActivatedListener[i];
                if (listener) listener(the_active_editor_ref);
            }
        } catch (e) {
        // NOTHING
        }
        this.updatePreviewBox();
    },
    
    /**
     * 
     */
    registerEditorActivatedListener: function (listener) {
        this.editorActivatedListener.push(listener);
    },

    /**
     *
     */
    unregisterMouseEvents: function () {
        var max = this.editors_ar.length;
        var j = 0;
        for (j=0; j < max; j++) {
            var editor = this.editors_ar[j];
            editor.unregisterEditorEvents();
        }
    },
    
    /**
     * Returns the active editor.
     * 
     * @return the active editorÃƒÆ’Ã†â€™Ãƒâ€ Ã¢â‚¬â„¢ÃƒÆ’Ã¢â‚¬Â ÃƒÂ¢Ã¢â€šÂ¬Ã¢â€žÂ¢ÃƒÆ’Ã†â€™ÃƒÂ¢Ã¢â€šÂ¬Ã…Â¡ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â¯ÃƒÆ’Ã†â€™Ãƒâ€ Ã¢â‚¬â„¢ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€¦Ã‚Â¡ÃƒÆ’Ã†â€™ÃƒÂ¢Ã¢â€šÂ¬Ã…Â¡ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â¿ÃƒÆ’Ã†â€™Ãƒâ€ Ã¢â‚¬â„¢ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€¦Ã‚Â¡ÃƒÆ’Ã†â€™ÃƒÂ¢Ã¢â€šÂ¬Ã…Â¡ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â½s reference
     */
    getActiveEditor: function() {
        if (this.active_editor == null) 
        {
            if (this.editors_ar.length > 0)
                this.active_editor = this.editors_ar[0];
        }
        return(this.active_editor);
    },
    
    /**
     * Returns the editor names.
     * 
     * @return editor_names: string[]
     */
    getEditorNames: function () {
        return(sh_extract_string_ar(this.editors_ar, 
            function (element) {
                return(element.getName());
            }
            ));
    },

    /**
     *
     */
    getEditorCount: function () {
        var number = this.editors_ar.length;
        return(number);
    },

    /**
     *
     */
    getEditorByIndex: function (index) {
        return(this.editors_ar[index]);  
    },

    preview_loaded: function () {
        var parent = this.box_image_ref.up();
        var newElement = this.previewEditor.html();

        parent.replaceChild(newElement, this.box_image_ref);
        $(this.previewEditor.getName()).show();

        // append page chooser
        if (this.chooser_div == null) {
            this.chooser_div = new Element("div", {
                "id": "prev_chooser"
            });
            var page_count = this.getEditorCount();
            if (page_count > 0) {
                var editor_label = this.getEditorByIndex(0).getName();
                this.chooser_div.innerHTML = '<div id="prev_chooser_name" style="font-weight: bold;">'+editor_label+'</div>';
                for (var i=0; i < page_count; i++) {
                    var label = this.getEditorByIndex(i).getName() + "   ";
                    var child = new Element("a", {});
                    this.append_Preview_Event(child, i);

                    child.appendChild(document.createTextNode(label));
                    this.chooser_div.appendChild(child);
                }
            }
        }
        Element.insert(parent, {
            "top": this.chooser_div
        });

        this.previewbox_initialized = true;
    },


    /**
     * Initialisiert den Preview-Box Editor.
     *
     * Das Bild wird gegen den Editor getauscht.
     *
     * !!! Darf erst aufgerufen werden, wenn der DOM-Teil geladen ist !!!
     */
    __initPreviewEditor: function () {
        // leave function if allready initialized
        if (this.previewbox_initialized) return;

        // get image from preview-box, use preview-div if not existing.
        this.box_image_ref = $('box_case_image_case');
        if (this.box_image_ref) {
        // nothing
        } else {
            this.box_image_ref = $('preview');
        }

        // if null leave this process and try it later again.
        if (this.box_image_ref == null) return;

        var counter = 0;
        var self = this;
        var step = function () {
            counter++;
            if (counter == 2) {
                self.preview_loaded();
            }
        };

        this.previewEditor = new _Editor("Preview", 180, 138, 0.00, 0.00, false, "/customer_images/Laptop/Deckel_Editor.gif", "/customer_images/Laptop/Deckel_Editor_back.gif", step, new _Viewport(0, 0, 180, 132));
        this.previewEditor.designer = this;
        this.previewEditorBig = new _Editor("Lupe", 580, 444, 0.00, 0.00, false, "/customer_images/Laptop/big2/Deckel_Editor.gif", "/customer_images/Laptop/big2/Deckel_Editor_back.gif", step, new _Viewport(0, 0, 580, 444));
        this.previewEditorBig.designer = this;
    },

    /**
     * Wird nach jedem EditorActivated-Event aufgerufen.
     *
     * Funktion aktualisiert die Darstellung in der
     *  Preview auf der rechten Seite.
     *
     * @return void
     */
    updatePreviewBox: function () {
        if (this.previewbox_initialized && (this.previewEditor != null) && (this.previewEditorBig != null)) {
            try {
                this.__updateSmallPreview();
            }catch (e) {
                alert("small_preview_ecx=" + e.description);
            }
            try {
                this.__updateBigPreview();
            } catch (e2) {
                alert("big_preview_exc=" + e2.description);
            }

            var editor_place = $('ce_big_preview');
            if (editor_place != null) {
                var parent = editor_place.up();
                var editor_div = this.previewEditorBig.html();
                parent.replaceChild(editor_div, editor_place);
                $(this.previewEditorBig.getName()).show();
            }
        }
    },

    /**
     * Create mini-editor view for shopping cart.
     */
    __generateShoppingCartEditor: function () {
    // TODO
    },

    /**
     *
     */
    __updateSmallPreview: function () {
        var currentEditor = this.getActiveEditor();

        // reset previeweditor
        this.previewEditor.clear();

        var f = 1.0;
        if (this.editor_type == "notebook") {
            f = 0.6207;
        } else {
            // no helper-mask for pc-case available
            this.previewEditor.removeHelperMask();
        }
        //        this.previewEditor = currentEditor.clone();
        //        this.previewEditor.scaleEditor(f);
        var mask = currentEditor.cloneMask();
        mask.scale(f);        
        this.previewEditor.changeMask(mask);

        var editor_panel_w = currentEditor.div.style.width.match(this.numberRegEx);
        var editor_panel_h = currentEditor.div.style.height.match(this.numberRegEx);
        editor_panel_w *= f;
        editor_panel_h *= f;
        this.previewEditor.setEditorSize(Math.round(editor_panel_w), Math.round(editor_panel_h));

        // skalierung übernehmen
        this.previewEditor.factor = currentEditor.factor;

        // display image if available
        if (currentEditor.image != null) {
            var image = this.previewEditor.image;
            if (image == null) {
                image = new Image();
                this.previewEditor.image = image;
                this.previewEditor._setImage(image);
            }

            this.previewEditor.image.src = currentEditor.image.src;

            var w_orig = currentEditor.image.style.width.match(this.numberRegEx);
            var h_orig = currentEditor.image.style.height.match(this.numberRegEx);
            w_orig *= f;
            h_orig *= f;
            this.previewEditor.image.style.width = Math.round(w_orig) + "px";
            this.previewEditor.image.style.height = Math.round(h_orig) + "px";

            // pos
            var orig_left = currentEditor.image.style.left.match(this.numberRegEx);
            var orig_top  = currentEditor.image.style.top.match(this.numberRegEx);
            orig_left *= f;
            orig_top *= f;
            this.previewEditor.image.style.left= Math.round(orig_left) + "px";
            this.previewEditor.image.style.top= Math.round(orig_top) + "px";

            this.previewEditor.changeBackgroundColor(currentEditor.backgroundColor);
        } else {
            this.previewEditor.changeBackgroundColor(currentEditor.backgroundColor);
        }

       
    },

    /**
     *
     */
    __updateBigPreview: function () {
        var currentEditor = this.getActiveEditor();

        // reset big-preview
        this.previewEditorBig.clear();

        // MANAGE BIG-Preview //
        ////////////////////////
        var f_big = 2.12; // WS - Default
        if (this.editor_type == "notebook") {
            f_big = 2.00;
            if (this.previewEditorBig.helper_image_ref != null) {
                try {
                    if (this.previewEditorBig.helper_image_ref != null) {
                        // get current editor-helper image
                        var path = currentEditor.helper_image_ref.src;
                        // change path to big version
                        var lastSlashIndex = path.lastIndexOf("/");
                        var subpath = path.slice(0, lastSlashIndex + 1);
                        var filename = path.slice(lastSlashIndex + 1);
                        path = subpath + "big2/" + filename;
                        
                        this.previewEditorBig.helper_image_ref.src = path;

                        // change mask_ref_iamge
                        if (currentEditor.mask_ref.image) {
                            path = currentEditor.mask_ref.image.src;
                            lastSlashIndex = path.lastIndexOf("/");
                            subpath = path.slice(0, lastSlashIndex + 1);
                            filename = path.slice(lastSlashIndex + 1);
                            path = subpath + "big2/" + filename;

                            this.previewEditorBig.mask_ref.image.src = path;
                        } else {
                            alert("keine maske!?");
                        }
                    }
                } catch (exc) {
                    alert("update big preview:" + exc);
                }
            }
        } else {
            // no helper-mask for pc-case available
            this.previewEditorBig.removeHelperMask();        

            var mask_big = currentEditor.cloneMask();
            mask_big.scale(f_big);
            this.previewEditorBig.changeMask(mask_big);

            var editor_panel_w_big = currentEditor.div.style.width.match(this.numberRegEx);
            var editor_panel_h_big = currentEditor.div.style.height.match(this.numberRegEx);
            editor_panel_w_big *= f_big;
            editor_panel_h_big *= f_big;
            this.previewEditorBig.setEditorSize(Math.round(editor_panel_w_big), Math.round(editor_panel_h_big));
        
            // skalierung übernehmen
            this.previewEditorBig.factor = currentEditor.factor;
        }

        // display image if available
        if (currentEditor.image != null) {
            // create new image reference
            var image_big = this.previewEditorBig.image;
            if (image_big == null) {
                image_big = new Image();
                this.previewEditorBig.image = image_big;
                this.previewEditorBig._setImage(image_big);
            }

            // get current image-path
            var path = currentEditor.path; // /customer_images/normal/
            // change path to big_preview
            path = path.replace(/normal\//, "big_preview/");
            // set image
            this.previewEditorBig.image.src = path + currentEditor.filename;

            // read current editors width and heights
            var w_orig_big = currentEditor.image.style.width.match(this.numberRegEx);
            var h_orig_big = currentEditor.image.style.height.match(this.numberRegEx);
            // scale to big-version
            w_orig_big *= f_big;
            h_orig_big *= f_big;
            // set image width and height
            this.previewEditorBig.image.style.width = Math.round(w_orig_big) + "px";
            this.previewEditorBig.image.style.height = Math.round(h_orig_big) + "px";

            // get current editors image position
            var orig_left_big = currentEditor.image.style.left.match(this.numberRegEx);
            var orig_top_big  = currentEditor.image.style.top.match(this.numberRegEx);
            // scale to big-version
            orig_left_big *= f_big;
            orig_top_big *= f_big;
            // set new left and top
            this.previewEditorBig.image.style.left= Math.round(orig_left_big) + "px";
            this.previewEditorBig.image.style.top= Math.round(orig_top_big) + "px";

            this.previewEditorBig.changeBackgroundColor(currentEditor.backgroundColor);
        } else {
            this.previewEditorBig.changeBackgroundColor(currentEditor.backgroundColor);
        }
    },

    /**
     *
     */
    append_Preview_Event: function (obj, id) {
        var self = this;
        var event = function (evt) {
            this.editor_id = id;
            try {
                if (self) {
                    var editor = self.getEditorByIndex(this.editor_id);
                    var editor_name = editor.getName();
                    var label = $('prev_chooser_name');
                    label.innerHTML = editor_name;

                    self.setActiveEditorByName(editor_name);
                    self.updatePreviewBox();
                }
            } catch (e) {
                alert("Preview_EXC=" + e.description);
            }
        };
        
        obj.onclick = event;
    },

    /**
     *
     */
    setSavingAnimation: function (is_saving) {
        try {
            // disable safe button and display a running gif
            var safe_button_ref = $('safe_button');
            var running_img_ref = $('running_img');
            if (safe_button_ref) {
                safe_button_ref.setOpacity(is_saving ? 0.3 : 1.0);
            }
            if (running_img_ref) {
                is_saving ? running_img_ref.show() : running_img_ref.hide();
            }
        } catch (animationException) {
            
        }
    },

    /**
     *
     */
    getCurrentProductId: function () {
        // get pid from cart_quantity form
        var product_id = 0;
        var form = $('cart_quantity');
        if (form) {
            var pid_input = form['products_id'];
            product_id = Form.Element.getValue(pid_input);
        } else {
            product_id = $('products_id').getValue();
        }
        //alert("PID=" + product_id);
        return(product_id);
    },
    
    /**
     * Store data but dont send cart-form.
     */
    storeOnly: function () {
        this.setSavingAnimation(true);

        this.isStored = false; // indicates wether the storage was successfully
        var left_data  = this.editors_ar[0].getConfigString();
        var front_data = this.editors_ar[1].getConfigString();
        var right_data = "";
        if (this.getEditorCount() > 2) {
            right_data = this.editors_ar[2].getConfigString();
        }
        //d("store_only designer_ref=" + this);
        //d("store_only editor_type=" + this.editor_type);
        var self = this;
        new Ajax.Request('/ajax_store.php', {
            method: 'post',
            parameters: {
                action: 'store_design',
                left: left_data,
                front: front_data,
                right: right_data,
                editor_type: this.editor_type,
                'product_id': this.getCurrentProductId(),
	                      
                store_id: this.store_id * 1,
                use_gallery: this.use_gallery,
                gallery_image: this.gallery_image
            },
            evalScripts: true
            ,
          
            onSuccess: function(transport) {
                //alert("ResultString: " + transport.responseText);
                var text = transport.responseText.evalJSON(true);
                self.store_id = text.store_id; // this != Designer at this point
                self.isStored = true;
                self.setSavingAnimation(false);
            },
            onFailure: function (transport) {
                self.setSavingAnimation(false);
                alert("Store failed: " + transport);
            },
            onException: function (transport, exc) {
                self.setSavingAnimation(false);
                alert("Store Exception=" + exc);
            }
        });
    },
    
    /**
     * Store current configuration in database.
     */
    storeInDatabase: function() {
        this.isStored = false; // indicates wether the storage was successfully
        var left_data  = this.editors_ar[0].getConfigString();
        var front_data = this.editors_ar[1].getConfigString();
        var right_data = "";
        if (this.getEditorCount() > 2) {
            right_data = this.editors_ar[2].getConfigString();
        }
        
        var top_data = this.editors_ar[0].getConfigString();
        var keyboard_data = this.editors_ar[1].getConfigString();

        var self = this;
        new Ajax.Request('/ajax_store.php', {
            method: 'post',
            parameters: {
                action: 'store_design',
                left: left_data,
                front: front_data,
                right: right_data,
                top: top_data,
                keyboard: keyboard_data,
                editor_type: this.editor_type,
	                      
                store_id: this.store_id * 1,
                use_gallery: this.use_gallery,
                gallery_image: this.gallery_image,
                'product_id': this.getCurrentProductId()
            },
            evalScripts: true,

            onSuccess: function(transport) {
                var text = transport.responseText.evalJSON(true);
                //alert("store result=" + text);
                self.store_id = text.store_id; // this != Designer at this point
                self.isStored = true;
                self._submit_cart();
            },
            onFailure: function (transport) {
                alert("Store failed: " + transport)
            },
            onException: function (transport, exc) {
                alert("Store Exception=" + exc);
            }
        });
    },
    
    clearAll: function () {
        var max = this.editors_ar.length;
        var j = 0;
        for (j=0; j < max; j++) {
            var editor = this.editors_ar[j];
            editor.clear();
        }
    },
    
    __html_entity_decode: function(str) {
        var ta=document.createElement("textarea");
        ta.innerHTML=str.replace(/</g,"&lt;").replace(/>/g,"&gt;");
        return ta.value;
    },

    /**
     * Create or replace a div-container for the designer information-box.
     */
    __initInfoBoxes: function () {
        try {
            if (this.infobox == null) {
                var buffer = $('ce_box_content');

                if (buffer == null) return;
            
                this.infobox = buffer;
                this.infobox.addClassName('box');
                this.infobox.addClassName('box_outline');

                var content = $('ce_right_box');
                this.infobox.innerHTML = content.innerHTML;
            
                this.small_pricebox = new Element("div", {
                    'id': 'small_pricebox'
                });
                this.small_pricebox.addClassName("box");
                this.small_pricebox.addClassName("box_outline");
                this.small_pricebox.style.textAlign = 'right';
            
                if (Prototype.Browser.IE) {
                    this.small_pricebox.style.marginTop = '30px';
                }
                var text_node = new Element('span', {
                    'id': 'ce_price'
                });
                text_node.addClassName("conf_price");
                text_node.appendChild(document.createTextNode(""));
                this.small_pricebox.appendChild(text_node);
            
                //var label = document.createTextNode(this.__html_entity_decode(" &euro;")); // &#x20AC;
                var label = new Element("span");
                label.appendChild(document.createTextNode(this.__html_entity_decode("&nbsp;&euro;&nbsp;")));
                label.addClassName("conf_price");
                this.small_pricebox.appendChild(label);
            
                var test = $('configurator').getElementsByClassName("price_hint");
                var block = new Element("div", {});
                block.appendChild(test[1].cloneNode(true));
                this.small_pricebox.appendChild(block);

                // insert Gesamtpreis: - Label
                var price_title = new Element("div", { });
                price_title.style.marginRight = "5px";
                var price_title_text = document.createTextNode("Gesamtpreis:");
                price_title.appendChild(price_title_text);
                Element.insert(this.small_pricebox, {
                    'top': price_title
                });

                Element.insert(this.infobox, {
                    'after': this.small_pricebox
                });
            
                // update price
                if (updatePrice) {
                    updatePrice();
                }
            
                this.infobox.show();
            }
        } catch (e) {
            alert("Init-Exc:" + e);
        }
    },

    /**
     * Call after dom loaded!!!
     */
    setCompleted: function () {
        try {
            this.__initInfoBoxes();
            this.__initPreviewEditor();
        } catch (Exception) {
            alert("setCompleted: " + Exception.description);
        }

        this.complete = true;
    },

    /**
     * Make all editors visible.
     */
    showAllEditors: function () {
        var count = this.getEditorCount();
        for (i=0; i < count; i++) {
            var editor = this.getEditorByIndex(i);
            editor.showEditor();
            editor.scaleEditor(0.5);
        }
    },

    showSmallPreviewImageList: function () {
        var count = this.getEditorCount();
        for (i=0; i<count; i++) {
          
        }
    },

    registerDesignLoadedListener: function (new_listener) {
        this.designLoadedListenerList.push(new_listener);
    },

    fireDesignLoaded: function () {
        this.designLoadedListenerList.each(function (listener) {
            listener();
        });
    },

    /**
     * Update the editor by an instance of @__DesignEntry
     */
    __updateEditorValues: function (editor_id, design_entry) {
        try {
            var later = function(me) {
                var editor = me.editors_ar[editor_id];
                editor.__updateEditorValues(design_entry);
            };

            later(this);

        } catch (updateException) {
            debug_("UpdateEditorException: " + updateException.description);
        }
    },
    
    /**
     * Load last configuration from database and display.
     */
    restoreFromDatabase: function () {
        if (!this.complete) return;
        this.loading = true;
        this.clearAll();

        // wrapper for restore-callback 
        //  this causes the THIS instance to be the current designers one in
        //   function restore_processResult(..)
        var self = this;
        var result_processor = function (transport) {
            self.restore_processResult(transport);
        };
        
        new Ajax.Request('/ajax_store.php', {
            method: 'post',
            parameters: {
                action: 'restore_design',
                'product_id': this.getCurrentProductId()
            },
            onSuccess: result_processor, //this.restore_processResult,
            onFailure: function (transport) {
                this.loading = false;
                alert("Restore failed=" + transport);
            },
            onException: function (transport, exc) {
                this.loading = false;
                alert("Restore exception2=" + exc);
            }
        });
    },
    
    /**
     * Split path to path + filename
     */
    __splitFullPath: function (path) {
        var result = new Object();
        
        var lastSlashIndex = path.lastIndexOf("/");

        result.path = path.slice(0, lastSlashIndex + 1);
        result.name = path.slice(lastSlashIndex + 1);

        return(result);
    },
    
    restoreById: function (design_id) {
        //if (!this.complete) return;
        this.loading = true;
        this.clearAll();

        var self = this;
        new Ajax.Request('/ajax_store.php', {
            method: 'post',
            parameters: {
                action: 'restore_design_ID',
                design_id: design_id
            },
            onSuccess: self.restore_processResult.bindAsEventListener(self),
            onFailure: function (transport) {
                alert("Restore failed=" + transport);
            },
            onException: function (transport, exc) {
                alert("Restore exception (id)=" + exc);
            }
        });
    },
    
    /*
    setEditorsVisibility: function (visible) {
        var max_editors = this.editors_ar.length;
        var j=0;
        for (j=0; j < max_editors; j++) {
            var tmp = this.editors_ar[j];
            if (visible) tmp.show(); else tmp.hide();
        }

        if (visible) {
            $('controls').show();
        } else {
            $('controls').hide();
        }
    },
    */
    
    /*setGalleryImage: function (image_name) {
        this.gallery_image = image_name;
        var gallery_image_div = $('gallery_image');
        var g_i_m = $('gallery_image_message');
        if (g_i_m) g_i_m.hide();

        var image = null;
        if ($('from_gallery')) {
            image = $('from_gallery');
        } else {
            image = document.createElement("img");
            image.setAttribute("id", "from_gallery")
            if (gallery_image_div) gallery_image_div.appendChild(image);
        }
        image.src = '/gallery_images/normal/' + image_name;
    },
    
    setGalleriesVisibility: function (visible) {
        var image_message = $('gallery_image_message');
        if (visible) {
            var gallery_image = $('gallery_image');
            if (this.gallery_image == "") {
                this.use_gallery = 1;
                if (image_message) image_message.show();
            } else {
                this.use_gallery = 1;
                if (image_message) image_message.hide();
            }
            
            this.setEditorsVisibility(false);
            
            if (gallery_image) gallery_image.show(); // $('gallery_image')
        } else {
            this.use_gallery = 0;
            this.setEditorsVisibility(true);
            var gallery_image_ = $('gallery_image');
            if (gallery_image_) gallery_image_.hide();
            //$('gallery_image_message').hide();
            if (image_message) image_message.hide();
        }
    },
    */
    
    /**
     *
     */
    createOutputImage: function () {
    // TODO: create image for printing
    }
}
);

// * SOME HELPER FUNCTIONS FOR ARRAY MANAGEMENT *
// **********************************************

function sh_search_ar(array, condition_callback) {
    var max = array.length;
    for (i=0; i < max; i++) {
        var tmp = array[i];
        if (condition_callback(tmp)) return(tmp);
    }
    return(null);
}

function sh_extract_string_ar(array, result_callback) {
    var result = new Array();
    var max = array.length;
    for (i=0; i < max; i++) {
        var tmp = array[i];
        result.push(result_callback(tmp));
    }
    return(result);
}

// DEBUG //
///////////
function debug(message) {
    $('debug').innerHTML = message;
}

function debug_(message) {
    $('debug').innerHTML = $('debug').innerHTML + message;
}

function debug_t(obj, message) {
    var name = obj.getName();
    debug_(name + ":" + message + " | ");
}