var formHandler;

Event.observe(window, 'load', function() {
	
	self.moveTo(0,0);
	self.resizeTo(screen.availWidth,screen.availHeight);

	formHandler = new FormHandler('frm', 'formHandler');
    var boek = new ReisDagboek({
    	beginStep: (typeof(payed) == 'undefined') ? 1 : 9,
    	transactionID: (typeof(transactionID) == 'undefined') ? false : transactionID,
    	onFinish: function() {
    		window.close();
    	}
    });
    if (typeof(payed) != 'undefined') {
    	boek.buttons.previous.hide();
    }

	formHandler.options.onStepIncomplete = boek.eventOnStepIncomplete.bind(boek);
	formHandler.options.onStepComplete = boek.eventOnStepComplete.bind(boek);
	
    // receive the prices
	if (typeof(payed) == 'undefined') {
		
		ReisDagboek.Costs.Receive();
		ReisDagboek.Costs.AddObserver(function(){
		
			if (this.removedLoader) {
				return;
			}
			
			Element.remove('loader');
			this.removedLoader = true;
		});
	} else {
		Element.remove('loader');
	}
});

Object.extend(Number.prototype, {
	
	price: function(ff) {
		
		var w = new String(Math.round(this * 100) / 100).replace('.', ',');
		
		if (/,[0-9]$/.test(w)) {
			return w+'0';
		} else if (!/,[0-9]{2}$/.test(w)) {
			return w+',00';
		} else {
			return w;
		}
	}
	
});

Class.Extend = function(base, sub) {
    sub.prototype.initializeBase = base.prototype.initialize;
    return Object.extend(sub.prototype, base.prototype);
};

var FormObserver = Class.create();
FormObserver.prototype = {
	
	initialize: function(form, options) {
	
		this.options = {
			interval: 0.4,
			onValueChanged: function() {},
			onElementBlurred: function() {}
		};
		Object.extend(this.options, options || {});
		
		this.form 		= $(form);
		this.elements 	= Form.getElements(this.form);
		this.elements.each(function(element) {
			element.previousValue = Form.Element.getValue(element);
			if (element.type == 'text') {
				element.observe('blur', function() {
					this.options.onElementBlurred(element, $F(element));
				}.bind(this));
			}
		}.bind(this));
		
		setInterval(this.onTimerEvent.bind(this), this.options.interval * 1000);
	},
	
	onTimerEvent: function() {
		
		this.elements.each(function(element) {
			var value = $F(element);
			var changed = (typeof(element.previousValue) == 'string' && typeof(value) == 'string') ?
				element.previousValue != value
			:
				String(element.previousValue) != String(value)
			;
			if (changed) {
				
				element.previousValue = value;
				this.options.onValueChanged(element, value);
			}
		}.bind(this));
	}
};

/**
 * The main class
 */
var ReisDagboek = Class.create();
ReisDagboek.prototype = {
    
    /**
     * Constructor
     *
     */
    initialize: function(options) {
        
        this.options = {
            onNext: function() {},
            onPrevious: function() {},
            onFinish: function() {},
            beginStep: 1,
            transactionID: false
        };
        Object.extend(this.options, options || {});
        
        // set variables
        this.bodyWrapElementElement    = $('wrap');
        this.centerElement      = $('center');
        this.leftPanelElement   = $('leftPanel');
        this.rightPanelElement  = $('rightPanel');
        this.contentContainers  = $A(this.rightPanelElement.getElementsByClassName('contentContainer'));
        this.stepItems          = [];
        this.contentContainers  = [];
        this.buttons            = {
        
            next: new ReisDagboek.Button({
                element: 'btnNext',
                onClick: this.eventOnNext.bind(this),
                disabled: true
            }),
            
            previous: new ReisDagboek.Button({
                element: 'btnPrevious',
                onClick: this.eventOnPrevious.bind(this),
                disabled: true
            })
        };
        
        // add all the stepitems / contentcontainers
        $A(this.leftPanelElement.getElementsByTagName('li')).each(function(element, index) {
            this.stepItems.push(new ReisDagboek.StepItem(element, index, {
                disabled: true,
                onClick: this.eventOnStepItemClick.bind(this)
            }));
        }.bind(this));
        $A(this.rightPanelElement.getElementsByClassName('contentContainer')).each(function(element, index) {
            
            var contentContainer;
            var contentContainerOptions = {
                onAppeared: this.eventOnContentContainerAppeared.bind(this),
                hidden: (index != this.options.beginStep - 1) // only visible page is the first one
            };
            
            // type of container
            if (element.hasClassName('firstPage')) {
                contentContainer = ReisDagboek.ContentContainer.FirstPage;
            } else if (element.hasClassName('introduction')) {
            	contentContainer = ReisDagboek.ContentContainer.Introduction;
            } else if (element.hasClassName('costs')) {
            	contentContainer = ReisDagboek.ContentContainer.Costs;
            } else if (element.hasClassName('layout')) {
            	contentContainer = ReisDagboek.ContentContainer.Layout;
            } else if (element.hasClassName('personalData')) {
            	contentContainer = ReisDagboek.ContentContainer.PersonalData;
            } else if (element.hasClassName('extra')) {
            	contentContainer = ReisDagboek.ContentContainer.Extra;
            } else if (element.hasClassName('payment')) {
            	contentContainer = ReisDagboek.ContentContainer.Payment;
            } else if (element.hasClassName('finished')) {
            	contentContainer = ReisDagboek.ContentContainer.Finished;
            	contentContainerOptions.transactionID = this.options.transactionID;
            } else {
                contentContainer = ReisDagboek.ContentContainer;
            }
            
            this.contentContainers.push(new contentContainer(element, contentContainerOptions));
        }.bind(this));

        // activate the first
        this.setCurrentStep(this.options.beginStep);
        
        // resize content + attatch resize on resizeevent of window
        setTimeout(function() {
	        
	        this.resizeContent(true);
	        
	        Event.observe(window, 'resize', this.eventOnWindowResize.bind(this));
	        
        }.bind(this), 100);
    },
    
    /**
     * Event which is raised when a step went incomplete.
     */ 
    eventOnStepIncomplete: function(step) {
    	
    	if (step == this.currentStep) {
    		this.buttons.next.disable();
    	}
    },
    
    /**
     * Event which is raised when a step went complete.
     */ 
    eventOnStepComplete: function(step) {
    	
    	if (step == this.currentStep) {
    		this.buttons.next.enable();
    	}
    },
    
    /**
     * Event which is raised when an contentcontainer has appeared.
     */
    eventOnContentContainerAppeared: function() {
        
        // overflow back to it's original value
        this.rightPanelElement.style.overflow = '';
    },
    
    /**
     * Event which is raised when the window resizes.
     */
    eventOnWindowResize: function(evt) {
        this.resizeContent(false);
    },
    
    /**
     * Event which is raised when the next-button is clicked.
     */
    eventOnNext: function() {
        
    	if (this.contentContainers[this.currentStep - 1].element.hasClassName('payment')) {
    		this.submitBook();
    	} else if (this.contentContainers[this.currentStep - 1].element.hasClassName('finished')) {
    		this.eventOnFinish();
    	} else {
    		
        	this.setCurrentStep(this.currentStep + 1);

	        this.options.onNext(false);
    	}
    },
    
    /**
     * Event which is raised when an stepitem is clicked.
     */
    eventOnStepItemClick: function(index) {
        this.setCurrentStep(index + 1);
    },
    
    /**
     * Event which is raised when the previous-button is clicked.
     *
     */
    eventOnPrevious: function() {
        
        this.setCurrentStep(this.currentStep - 1);
        
        this.options.onPrevious(false);
    },
    
    /**
     * Event which is raised when the finished-button was pressed.
     */
    eventOnFinish: function() {
    	
    	this.options.onFinish();
    },
    
    /**
     * Event which is raised when the booksubmition completed.
     */
	eventBookSubmitComplete: function(result) {
		
		for (var name in this.buttons) {
    		this.buttons[name].enable();
		}
		formHandler.enableAll();
		$(document.body).removeClassName('disabled');
    	
		// prevent the user to go back
		for (var i = 0; i < this.currentStep; i++) {
			this.stepItems[i].deactivate();
		}
		this.buttons.previous.hide();
		
		if (result.issuerURL) {
			document.location.href = result.issuerURL;
		} else if (result.error) {
			alert(result.error);
		} else {
			alert('Fout bij het opslaan.');
		}
	},
    
    /**
     * Sets the current step.
     *
     * @param int step the stepnumber
     */
    setCurrentStep: function(step) {
        
        if (step < 1 || step > this.stepItems.length) {
            return;
        }
        
        if (step >= 2) {
            this.buttons.previous.enable();
        } else {
            this.buttons.previous.disable();
        }
        
        if (step <= this.stepItems.length && (!formHandler || !formHandler.steps[step] || formHandler.steps[step].valid)) {
            this.buttons.next.enable();
        } else {
            this.buttons.next.disable();
        }
        
        if (this.currentStep) {
        	
        	if (this.currentStep == this.stepItems.length) {
        		this.buttons.next.setValue('Volgende �');
        	}
            
            this.stepItems[this.currentStep - 1].deactivate();
        
            // hide scrollbars during appearance
            this.rightPanelElement.style.overflow = 'hidden';
            this.rightPanelElement.scrollTop = 0;
            
            this.contentContainers[this.currentStep - 1].disappear(step < this.currentStep);
            this.contentContainers[step - 1].appear(step > this.currentStep);
            
        } else {
        	this.contentContainers[step - 1].eventOnAppeared();
        }
        
        this.stepItems[step - 1].activate();
        
        this.currentStep = step;
        
    	if (this.currentStep == this.stepItems.length) {
    		this.buttons.next.setValue('Voltooien');
    	}
    },
    
    /**
     * Resizes the content based on the size of the window.
     */
    resizeContent: function() {

    	var diffY = document.body.offsetHeight - this.bodyWrapElementElement.offsetHeight;
        var diffX_rightPanel = document.body.offsetWidth - this.leftPanelElement.offsetWidth;
        
        this.centerElement.style.height = (diffY + this.centerElement.offsetHeight)+'px';
        this.centerElement.style.width = document.body.offsetWidth+'px';
		
        this.rightPanelElement.style.width = diffX_rightPanel+'px';
    },
    
    /**
     * Submits whole the book.
     */
    submitBook: function() {
    	
		for (var name in this.buttons) {
    		this.buttons[name].disable();
		}
    	formHandler.submit('?action=submit', this.eventBookSubmitComplete.bind(this));
    	
		formHandler.disableAll();
		$(document.body).addClassName('disabled');
		
    }
};

/**
 * This provides functionality for placing a loader over a element.
 */
ReisDagboek.Loader = Class.create();
ReisDagboek.Loader.prototype = {
	
	initialize: function() {
		
		this.containerElement = $(document.createElement('DIV'));
		this.containerElement.style.position = 'absolute';
		this.containerElement.style.width = '43px';
		this.containerElement.style.height = '11px';
		this.containerElement.style.background = 'transparent url(/images/boek/load_small.gif) no-repeat';
		this.containerElement.style.display = 'none';
	},
	
	show: function(element) {
		
		if (!element) {
			return;
		}
		
		elemenet = $(element);
		
		if (this.containerElement.visible()) {
			this.hide();
		}

		this.containerElement.style.display = 'block';
		
		element.parentNode.insertBefore(this.containerElement, element);
		
		Position.clone(element, this.containerElement, {setWidth: false, setHeight: false});
		
		element.style.visibility = 'hidden';
		
		this.currentElement = element;
	},
	
	hide: function() {
	
	    if (!this.containerElement.parentNode) {
	        return false;
	    }
		
		if (this.currentElement) {
			this.currentElement.style.visibility = 'visible';
		}
		
		this.containerElement.style.display = 'none';
		this.containerElement.remove();
	}
};

/**
 * The class which handles the validation of the main form.
 */
var FormHandler = Class.create();
FormHandler.prototype = {
	
	initialize: function(form, formHandler, options) {
		
		this.options = {
			onStepIncomplete: function() {},
			onStepComplete: function() {}
		};
		Object.extend(this.options, options || {});
		
		this.steps = {
			1: {
				valid: true,
				elements: {}
			},
			2: {
				valid: false,
				elements: {
					'title': {
						validator: this.validateTitle.bind(this),
						valid: false
					},
					'subtitle': {
						validator: this.validateSubtitle.bind(this),
						valid: false
					},
					'frontpageImage2': {
						validator: this.validateFrontPageImage.bind(this),
						valid: false
					},
					'frontpageImage3': {
						validator: this.validateFrontPageImage.bind(this),
						valid: false
					},
					'frontpageImage4': {
						validator: this.validateFrontPageImage.bind(this),
						valid: false
					},
					'frontpageImage5': {
						validator: this.validateFrontPageImage.bind(this),
						valid: false
					}
				}
			},
			3: {
				valid: false,
				elements: {
					'introImage': {
						validator: this.validateIntroductionImage.bind(this),
						valid: false
					},
					'introductionText': {
						validator: this.validateIntroductionText.bind(this),
						valid: false
					}
				}
			},
			4: {
				valid: false,
				elements: {
					'layout': {
					    validator: this.validateLayout.bind(this),
						valid: false
					}
				}
			},
			5: {
				valid: true,
				elements: {
					'includeGuestbook': {
						valid: true
					}
				}
			},
			6: {
				valid: true,
				elements: {
					'amount': {
						validator: this.validateAmount.bind(this),
						valid: false
					}
				}
			},
			7: {
				valid: true,
				elements: {
					'fname': {
						validator: this.validateFName.bind(this),
						valid: false
					},
					'lname': {
						validator: this.validateLName.bind(this),
						valid: false
					},
					'address': {
						validator: this.validateAddress.bind(this),
						valid: false
					},
					'housenumber': {
						validator: this.validateHouseNumber.bind(this),
						valid: false
					},
					'pcode': {
						validator: this.validatePCode.bind(this),
						valid: false
					},
					'city': {
						validator: this.validateCity.bind(this),
						valid: false
					},
					'email': {
						validator: this.validateEmail.bind(this),
						valid: false
					},
					'dAddress': {
						validator: this.validateDAddress.bind(this),
						valid: true
					},
					'd_fname': {
						validator: this.validateD_FName.bind(this),
						valid: false
					},
					'd_lname': {
						validator: this.validateD_LName.bind(this),
						valid: false
					},
					'd_address': {
						validator: this.validateD_Address.bind(this),
						valid: false
					},
					'd_housenumber': {
						validator: this.validateD_HouseNumber.bind(this),
						valid: false
					},
					'd_pcode': {
						validator: this.validateD_PCode.bind(this),
						valid: false
					},
					'd_city': {
						validator: this.validateD_City.bind(this),
						valid: false
					},
					'acceptAgreement': {
						validator: this.validateAcceptAgreement.bind(this),
						valid: false
					}
				}
			},
			8: {
				valid: false,
				elements: {
					'bank': {
						validator: this.validateBank.bind(this),
						valid: false
					}
				}
			}
		};
		
		this.form 				= $(form);
		this.handler 			= $(formHandler);
		
		if (this.handler.window) {
			this.handlerWindow	= this.handler.window;
		} else if (this.handler.contentWindow) {
			this.handlerWindow	= this.handler.contentWindow;
		} else {
			this.handlerWindow = this.handler;
		}
		
		// process every element
		for (var step in this.steps) {
			for (var elementName in this.steps[step].elements) {
				this.processElement(elementName, 0);
			}
		}

		this.handler.observe('load', this.eventOnFormHandlerLoad.bind(this));
		
        // initialise formobserver for when a value has changed
		new FormObserver(this.form, {
			interval: 0.2,
			onValueChanged: this.eventOnFormdataChanged.bind(this),
			onElementBlurred: this.eventOnFormElementBlurred.bind(this)
		});
	},
	
	/**
	 * Event is raised when the formhandler finished processing its request.
	 */
	eventOnFormHandlerLoad: function() {

		if (this.handlerWindow.Result) {
			var result = this.handlerWindow.Result();
			this.onFinished(result);
		}
		
		this.onFinished = false;
	},
	
	/**
	 * Enables every element in the form.
	 */
	enableAll: function() {
		
		var elements = this.form.getElements();
			
		for (var i = 0; i < elements.length; i++) {
			elements[i].disabled = false;
		}
	},
	
	/**
	 * Disables every element in the form.
	 */
	disableAll: function() {
		
		var elements = this.form.getElements();
			
		for (var i = 0; i < elements.length; i++) {
			elements[i].disabled = true;
		}
	},
	
	/**
	 * Submits the form to the given location and then calls back the given function.
	 */
	submit: function(location, onFinished, target) {
		
		// means another submit is already being processed
		if (this.onFinished) {
			return;
		}
		
		if (target) {
			this.form.target = target;
		} else {
			this.onFinished = onFinished || function() {};
			this.form.target = 'formHandler';
		}
		
		this.form.action = location;
		this.form.submit();
	},
	
	/**
	 * Sets the value of the given element.
	 */
	setValue: function(element, value) {

		if (this.form[element]) {
			this.form[element].value = value;
		}
	},
	
	/**
	 * Gets the value of the given element.
	 */
	getValue: function(element) {
		
		if (typeof(element) != 'object') {
			element = this.getElement(element);
		}
		return (element) ? $F(element) : '';
	},
	
	/**
	 * Gets the step of the given element.
	 */
	getElementStep: function(element) {

		for (var step in this.steps) {
			if (this.steps[step].elements[element.name]) {
				return step;
			}
		}
		return false;
	},
	
	/**
	 * Checks if the given step is valid.
	 */
	stepIsValid: function(step) {
		
		//if (typeof(t) != 'undefined') return true; // DEBUG
		
		var elements = this.steps[step].elements;
		
		for (var elementName in elements) {
			if (!elements[elementName].valid) {
				return false;
			}
		}
		return true;
	},
	
    /**
     * Event which is raised when the value of a form-element has changed.
     */
	eventOnFormdataChanged: function(element, value) {
		this.processElement(element, 1);
	},
	
    /**
     * Event which is raised when a form-element lost it's focus.
     */
	eventOnFormElementBlurred: function(element, value) {
		this.processElement(element, 2);
	},
	
	/**
	 * Gets the element based on the given name.
	 */
	getElement: function(name) {
		
		element = $(this.form[name]);

		if (typeof(element[0]) == 'object' && element[0] != null && element[0].type == 'radio') {
			
			for (var i = 0; i < element.length; i++) {
				if (element[i].checked) {
					return element[i];
				}
			}
			return element[0];
		}
		return element;
	},
	
	/**
	 * Processes the given element.
	 */
	processElement: function(element, validationLevel) {
		
		if (typeof(element) != 'object') {
			element = this.getElement(element);
		}

		value = $F(element);
		
		// if the element doesnt know yet what step he is
		if (!element.step) {
			
			// let him know..
			var step = this.getElementStep(element);
			
			if (!step) {
				return;
			}
			
			element.step = step;
		}
		
		var elementStep  = this.steps[element.step];
		var validateData = this.steps[element.step].elements[element.name];
		
		if (validateData) {
			
			// if the value did not pass it's validation
			if (validateData.validator && !validateData.validator(value, element)) {
				
				if (validateData.valid) {
					
					// set the element itself to invalid
					validateData.valid = false;
					
					if (validationLevel > 0) {
						
						// fire specific event that the element went invalid
						if (this.options['on'+new String(element.name).capitalize()+'Invalid']) {
							this.options['on'+new String(element.name).capitalize()+'Invalid'](element, value);
						}
					}
					
				} else if (validationLevel > 0 && (elementStep.valid || validationLevel == 2)) {
					
					// fire specific event that the element went invalid
					if (this.options['on'+new String(element.name).capitalize()+'Invalid']) {
						this.options['on'+new String(element.name).capitalize()+'Invalid'](element, value);
					}
				}
				
				// if the step of the element was valid
				if (elementStep.valid) {
					
					// set the step to invalid
					elementStep.valid = false;
					
					// let the observe know a step went incomplete
					this.options.onStepIncomplete(element.step);
				}
				
			} else if (!validateData.valid) {
				
				if (validationLevel > 0) {
					
					// fire specific event that the element went valid
					if (this.options['on'+new String(element.name).capitalize()+'Valid']) {
						this.options['on'+new String(element.name).capitalize()+'Valid'](element, value);
					}
				}
				
				// set the element itself to valid
				validateData.valid = true;
			}
		}
				
		// if the step of the element went complete
		if (this.stepIsValid(element.step)) {
			
			// mark the step as valid
			elementStep.valid = true;
			
			// let the observe know a step went complete
			this.options.onStepComplete(element.step);
		}
	},
	
	/**
	 * Validates the title.
	 */
	validateTitle: function(value, element) {
		return (value != '');
	},
	
	/**
	 * Validates the subtitle.
	 */
	validateSubtitle: function(value, element) {
		return (value != '');
	},
	
	/**
	 * Validates the value of an inputfield of a frontpage image.
	 */
	validateFrontPageImage: function(value, element) {
		return /\.(jpe?g|gif|png)$/i.test(value);
	},
	
	/**
	 * Validates the introduction image.
	 */
	validateIntroductionImage: function(value, element) {
		return /\.(jpe?g|gif|png)$/i.test(value);
	},
	
	/**
	 * Validates the value the introductiontext.
	 */
	validateIntroductionText: function(value, element) {
		return (value != '');
	},
	
	/**
	 * Validates the amount.
	 */
	validateAmount: function(value, element) {
		
		var tester = /([1-9][0-9]*)/;
		if (!tester.test(value)) {
			element.value = '';
			return false;
		}
		
		element.value = tester.exec(value)[1];
		
		if (element.value < 0 || element.value > ReisDagboek.Costs.MaxAmount) {
			return false;
		}
		
		return true;
	},
	validateLayout: function(value, element) {
	    return (value == 'budget' || value == 'premium');
	},
	validateFName: function(value, element) {
		return (value != '');
	},
	
	validateLName: function(value, element) {
		return (value != '');
	},
	
	validateAddress: function(value, element) {
		return (value != '');
	},
	
	validateHouseNumber: function(value, element) {
		return /^[0-9]+[\s[a-z0-9]*$/i.test(value);
	},
	
	validatePCode: function(value, element) {
		return (/^[0-9]{4} ?[a-z]{2}$/i.test(value));
	},
	
	validateCity: function(value, element) {
		return (value != '');
	},
	
	validateEmail: function(value, element) {
		return (/^([a-z0-9_\-\.]+)@([a-z0-9_\-\.]+)\.([a-z]{2,5})$/i.test(value));
	},
	
	validateDAddress: function(value, element) {

		this.processElement('d_fname', 0);
		this.processElement('d_lname', 0);
		this.processElement('d_address', 0);
		this.processElement('d_housenumber', 0);
		this.processElement('d_pcode', 0);
		this.processElement('d_city', 0);
		
		return true;
	},
	
	validateD_FName: function(value, element) {
		
		if (this.getValue('dAddress') == '1') {
			return this.validateFName(value, element);
		}
		return true;
	},
	
	validateD_LName: function(value, element) {
		
		if (this.getValue('dAddress') == '1') {
			return this.validateLName(value, element);
		}
		return true;
	},
	
	validateD_Address: function(value, element) {
		
		if (this.getValue('dAddress') == '1') {
			return this.validateAddress(value, element);
		}
		return true;
	},
	
	validateD_HouseNumber: function(value, element) {
		
		if (this.getValue('dAddress') == '1') {
			return this.validateHouseNumber(value, element);
		}
		return true;
	},
	
	validateD_PCode: function(value, element) {
		
		if (this.getValue('dAddress') == '1') {
			return this.validatePCode(value, element);
		}
		return true;
	},
	
	validateD_City: function(value, element) {
		
		if (this.getValue('dAddress') == '1') {
			return this.validateCity(value, element);
		}
		return true;
	},
	
	validateAcceptAgreement: function(value, element) {
		return (value == 1);
	},
	
	validateBank: function(value, element) {
		return (value != '');
	}
};

/**
 * A specific button for ReisDagboek.
 */
ReisDagboek.Button = Class.create();
ReisDagboek.Button.prototype = {
    
    /**
     * Constructor
     */
    initialize: function(options) {
        
        this.options = {
            element: false,
            value: false,
            href: 'javascript:void(0);',
            onClick: function() {},
            onFocus: function() {},
            onBlur: function() {},
            disabled: false,
            type: 'button',
            hidden: false,
            parent: document.body,
            insertBefore: false
        };
        Object.extend(this.options, options || {});
        
        // set variables
        if (this.options.element) {
            
            this.element            = $(this.options.element);
            this.innerButtonElement = $(this.element.getElementsByTagName('input')[0]);
            
        } else {
            
            this.element = $(document.createElement('A'));
            this.element.className = 'button';
            this.element.href = this.options.href;
            
            this.innerButtonElement = $(document.createElement('INPUT'));
            this.innerButtonElement.type = this.options.type;
            
            this.element.appendChild(this.innerButtonElement);
            
        }

        // add the element to a parent
        if (!this.element.parentNode && this.options.parent) {

            if (this.options.insertBefore) {
                this.options.parent.insertBefore(this.element, this.options.insertBefore);
            } else {
                this.options.parent.appendChild(this.element);
            }
        }
                
        // attach event
        Event.observe(this.innerButtonElement, 'click', this.eventOnClick.bind(this));
        Event.observe(this.innerButtonElement, 'focus', this.eventOnFocus.bind(this));
        Event.observe(this.innerButtonElement, 'blur', this.eventOnBlur.bind(this));
        
        // handle options
        if (this.options.disabled) {
            this.disable();
        }
        if (this.options.hidden) {
            this.hide();
        }
        if (this.options.value) {
            this.setValue(this.options.value);
        }
    },
    
    /**
     * Event which is raised when the button is clicked
     *
     */
    eventOnClick: function(evt) {
        this.options.onClick(evt);
    },
    
    /**
     * Event which is raised when the button is focused
     *
     */
    eventOnFocus: function(evt) {
        this.options.onFocus(evt);
    },
    
    /**
     * Event which is raised when the button lost focus
     *
     */
    eventOnBlur: function(evt) {
        this.options.onBlur(evt);
    },
    
    /**
     * Sets the value of the button.
     *
     * @param string value the value to be set
     */
    setValue: function(value) {
        this.innerButtonElement.value = value;
    },
    
    /**
     * Disables the button.
     *
     */
    disable: function() {
        
        this.element.addClassName('disabled');
        this.innerButtonElement.disabled = true;
        
        this.disabled = true;
    },
    
    /**
     * Enables the button.
     *
     */
    enable: function() {
        
        this.element.removeClassName('disabled');
        this.innerButtonElement.disabled = false;
        
        this.disabled = false;
    },
    
    /**
     * Hides the button.
     */
    hide: function() {
        this.element.hide();
    },
    
    /**
     * Shows the button.
     */
    show: function() {
        this.element.show();
    }
};

/**
 * A step indicator / link on the left panel.
 *
 */
ReisDagboek.StepItem = Class.create();
ReisDagboek.StepItem.prototype = {
    
    /**
     * The constructor
     *
     */
    initialize: function(element, index, options) {
        
        this.options = {
            disabled: false,
            activated: false,
            onClick: function() {}
        };
        Object.extend(this.options, options || {});
    
        // set variables
        this.element        = $(element);
        this.disabled       = false;
        this.index          = index;
        
        // attatch events
        Event.observe(this.element, 'click', this.eventOnClick.bind(this));
        Event.observe(this.element, 'mouseover', this.eventOnMouseOver.bind(this));
        Event.observe(this.element, 'mouseout', this.eventOnMouseOut.bind(this));
        
        // handle options
        if (!this.options.activated) {
            this.deactivate();
        }
        if (this.options.disabled) {
            this.disable();
        } else {
            this.enable();
        }
    },
    
    /**
     * Event which is raised when the item is clicked.
     *
     */
    eventOnClick: function(evt) {
        
        if (this.disabled || this.activated) {
            Event.stop(evt);
            return;
        }

        this.options.onClick(this.index, evt, this);
    },
    
    /**
     * Event which is raised when the mouse is over the item.
     *
     */
    eventOnMouseOver: function(evt) {
        
        if (this.disabled || this.activated) {
            Event.stop(evt);
            return;
        }
        
        this.element.addClassName('mouseover');
    },
    
    /**
     * Event which is raised when the mouse leaves the item.
     *
     */
    eventOnMouseOut: function(evt) {
        this.element.removeClassName('mouseover');
    },
    
    /**
     * Activates the item.
     *
     */
    activate: function() {
        
        if (this.disabled) {
            this.enable();
        }
        
        this.element.addClassName('activated');
        
        this.activated = true;
    },
    
    
    /**
     * Deactivates the item.
     *
     */
    deactivate: function() {
        
        this.element.removeClassName('activated');
        
        this.activated = false;
    },
    
    /**
     * Disables the item. Item can not be clicked if disabled.
     *
     */
    disable: function() {
        
        if (this.activated) {
            this.deactivate();
        }
        
        this.element.removeClassName('enabled');
        
        this.disabled = true;
    },
    
    /**
     * Enables the item.
     *
     */
    enable: function() {
        
        this.element.addClassName('enabled');
        
        this.disabled = false;
    }
};

/**
 * An content container.
 */
ReisDagboek.ContentContainer = Class.create();
ReisDagboek.ContentContainer.prototype = {

    initialize: function(element, options) {
        
        this.options = {
            hidden: false,
            onAppeared: function() {},
            onDisappeared: function() {}
        };
        Object.extend(this.options, options || {});
    
        // set variables
        this.element       = $(element);
        this.parentElement = this.element.offsetParent;
        
        // handle options
        if (this.options.hidden) {
            this.hide();
        }
    },
    
    /**
     * Event is raised when the container fully appeared.
     */
    eventOnAppeared: function() {
    	
        this.element.setStyle({
            height: 'auto'
        });
        
        this.options.onAppeared();
    },
    
    /**
     * Event is raised when the container fully disappeared.
     */
    eventOnDisappeared: function() {
        
        this.element.setStyle({
            display: 'none',
            height: 'auto'
        });
        
        this.options.onDisappeared();
    },
    
    /**
     * Let's the container appear in 0.5 seconds.
     *
     * @param boolean fromBottom should the element appear from the bottom
     */
    appear: function(fromBottom) {
        
        var targetStartPosition = this.parentElement.offsetHeight;
        if (!fromBottom) {
            targetStartPosition *= -1;
        }
        
        if (this.currentMovement) {
        	this.currentMovement.cancel();
        }

        this.element.setStyle({
            top: targetStartPosition+'px',
            height: this.parentElement.offsetHeight+'px',
            display: 'block'
        });

        this.currentMovement = new Effect.MoveBy(this.element, targetStartPosition * -1, 0, {
            duration: 0.5,
            transition: Effect.Transitions.linear,
            afterFinish: this.eventOnAppeared.bind(this)
        });
    },
    
    /**
     * Let's the container disappear in 0.5 seconds.
     *
     * @param boolean toBottom should the element disappear to the bottom
     */
    disappear: function(toBottom) {
        
        var targetPosition = this.parentElement.offsetHeight;
        if (!toBottom) {
            targetPosition *= -1;
        }
        
        if (this.currentMovement) {
        	this.currentMovement.cancel();
        }

        this.element.setStyle({
            height: this.parentElement.offsetHeight+'px'
        });
        
        this.currentMovement = new Effect.MoveBy(this.element, targetPosition, 0, {
            duration: 0.5,
            transition: Effect.Transitions.linear,
            afterFinish:  this.eventOnDisappeared.bind(this)
        });
    },
    
    /**
     * Hides the container.
     */
    hide: function() {
        this.element.hide();
    },
    
    /**
     * Shows the container.
     */
    show: function() {
        this.element.show();
    }
};

/**
 * The contentcontainer for the introductionpage.
 */
ReisDagboek.ContentContainer.Introduction = Class.create();
Object.extend(Class.Extend(ReisDagboek.ContentContainer, ReisDagboek.ContentContainer.Introduction), {

    initialize: function(element, options) {
        
        this.initializeBase(element, options);
        
        this.imageContainerValueHolder	= $('introImage');
        this.imageInputContainerElement = $('introductionImageInputContainer');
        this.imageContainerElement 		= $('introductionImageContainer');
        this.imageInputElement			= $('introductionImageInput');
        this.imageElement				= $('introductionImage');
        this.textInputElement			= $('introductionText');
        this.btnReplaceImage			= new ReisDagboek.Button({
        	element: 'replaceIntroductionImageButton',
        	onClick: this.eventOnReplaceImageClick.bind(this)
        });
		this.loader = new ReisDagboek.Loader();
        
        this.imageInputElement.observe('change', this.eventOnImageChange.bind(this));
        this.textInputElement.observe('change', this.eventOnTextChange.bind(this));
        
		this.imageElement.observe('load', this.eventOnImageLoaded.bind(this));
        
        this.imageInputElement.style.visibility = 'hidden';
		this.imageContainerElement.style.display = 'none';
	},
    
    /**
     * Event is raised when the container fully appeared.
     */
    eventOnAppeared: function() {
    
        this.element.setStyle({
            height: 'auto'
        });
        
    	if (!this.personalDataSet) {
    		
    		this.loader.show(this.imageInputElement);
    		
	        new Ajax.Request('boek.php?action=getPersonalData', {
	        	onComplete: this.eventOnAjaxPersonalDataComplete.bind(this)
	        });
	        
	        this.personalDataSet = true;
        }
    },
    
    /**
     * Event is raised when the ajaxrequest for getting the personal data returned.
     */
    eventOnAjaxPersonalDataComplete: function(response) {
    	
    	var result = eval('('+response.responseText+')');
    	
		this.loader.hide();
		
    	if (!result.error) {
    		if (result.picture) {
    			this.setImage(result.picture);
    		}
    		this.textInputElement.value = result.personal_message;
    	}
    },
    
    /**
     * Event is raised when the user changed the introductiontext.
     */
    eventOnTextChange: function() {
    },
    
    /**
     * Event is raised when the user selected a different image.
     */
    eventOnImageChange: function() {
    	
    	this.loader.show(this.imageInputElement);
    	
    	formHandler.submit('?action=setIntroductionImage', this.eventOnImageSubmitComplete.bind(this));
    },
    
    /**
     * Event is raised when the submition of the picture is complete.
     */
    eventOnImageSubmitComplete: function(response) {
 
    	this.imageInputElement.value = '';
    	
		this.loader.hide();
    	
    	if (response.error) {
    	
    		alert(response.error);
    		
   		} else {
   			this.setImage(response.picture);
    	}
    },
    
    /**
     * Event is raised when the image is loaded after it being set.
     */
    eventOnImageLoaded: function() {
		
    	this.imageLoading = false;

		this.imageContainerElement.style.display = 'block';
		
    	if (this.imageElement.width > this.imageElement.height && this.imageElement.width > 150) {
    		this.imageElement.style.height = 'auto';
    		this.imageElement.style.width = '150px';
    		
    	} else if (this.imageElement.height > this.imageElement.width && this.imageElement.height > 150) {
    		this.imageElement.style.width = 'auto';
    		this.imageElement.style.height = '150px';
    		
    	}
		
		this.imageInputContainerElement.hide();
		
		Effect.Appear(this.imageContainerElement);
		this.imageContainerElement.show();

		this.textInputElement.focus();
    },
    
    /**
     * Event is raised when the user clicked the button for replacing the current image.
     */
    eventOnReplaceImageClick: function() {
    	
		Effect.Fade(this.imageContainerElement, {
			duration: 0.5,
			afterFinish: function() {
				Effect.Appear(this.imageInputContainerElement, {
					duration: 0.5
				});
			}.bind(this)
		});
    },
    
    /**
     * Sets the current image.
     */
    setImage: function(image) {

    	this.imageContainerValueHolder.value = image;
    	this.imageElement.src = image;
    	
    	this.imageLoading = true;
    }
});

ReisDagboek.Costs = {
	
	observers: [],
	
	Amount: 1,
	
	AddObserver: function(observer) {
		
		if (this.observers.indexOf(observer) == -1) {
			this.observers.push(observer);
		}
	},
	
	Update: function() {
		
		this.Pages_noGuestbook 	= this.TotalPages - this.GuestbookPages;
		this.GuestbookPrice 	= this.Price - this.Price_noGuestbook;
	
		if (this.IncludeGuestbook) {
			this.ActualPages = this.TotalPages;
			this.ActualPrice = this.Price;
		} else {
			this.ActualPages = this.Pages_noGuestbook;
			this.ActualPrice = this.Price_noGuestbook;
		}
		
		this.PartCount = Math.ceil(this.ActualPages / 260);
		this.MaxAmount = Math.floor(10 / this.PartCount);
		
		// voor & achhterkant per extra deel
		this.ActualPages += (this.PartCount - 1) * 4;
		
		if (this.ActualPages <= 130 && this.Amount <= 2) {
			this.ActualSendCosts = this.SendCosts_small * this.Amount;
		} else {
			this.ActualSendCosts = this.SendCosts_large;
		}
		
		if (this.Discount) {
			this.ActualPrice -= this.Discount;
		}
		
		if (this.IncludeDigitalFiles) {
			this.ActualPrice += this.Digital;
		}
		
		this.ActualTotalPrice = this.Amount * this.ActualPrice;
		this.ActualTotalPrice += this.ActualSendCosts;
		
		this.observers.each(function(observer) {
			observer(this);
		}.bind(this));
	},
	
	Receive: function(budget) {
		
    	new Ajax.Request('boek.php?action=albumPrice'+((budget) ? '&budget=1' : ''), {
    		onComplete: function(response) {
    			
    			var result = eval('('+response.responseText+')');
    			
    			this.TotalPages 		= new Number(result.totalPages);
    			this.GuestbookPages		= new Number(result.guestbookPages);
		    	this.SendCosts_large 	= new Number(result.sendCosts_large);
		    	this.SendCosts_small 	= new Number(result.sendCosts_small);
		    	this.Price 				= new Number(result.price);
		    	this.Price_noGuestbook	= new Number(result.price_noguestbook);
		    	this.Discount			= (result.discount) ? new Number(result.discount) : 0;
		    	this.Digital			= new Number(result.digital);
    			
		    	this.Update();

    		}.bind(this)
    	});
	}
	
};

/**
 * The contentcontainer for the costspage.
 */
ReisDagboek.ContentContainer.Costs = Class.create();
Object.extend(Class.Extend(ReisDagboek.ContentContainer, ReisDagboek.ContentContainer.Costs), {

    initialize: function(element, options) {
        
        this.initializeBase(element, options);
        
        this.loader = new ReisDagboek.Loader();
        
        this.previewLinkElement					= $('previewLink');
        this.largebookCostsContainerElement		= $('largebookCostsContainer');
        this.bookPartCountElement				= $('bookPartCount');
        this.maxAmountElement					= $('maxAmount');
        this.amountInputElement					= $('amount');
        this.amountWrapElement 					= $('amountWrap');
        this.pagesTextElement 					= $('pagesText');
        this.actualPagesTextElement 			= $('actualPagesText');
		this.includeGuestbookContainerElement 	= $('includeGuestbookContainer');
		this.guestbookPriceTextElement			= $('guestbookPriceText');
		this.guestbookPagesTextElement			= $('guestbookPagesText');
		this.includeDigitalContainerElement 	= $('includeDigitalContainer');
		this.digitalPriceTextElement			= $('digitalPriceText');
        this.discountContainerElement			= $('discountContainer');
        this.discountTextElement				= $('discountText');
        this.sendCostsTextElement 				= $('sendCostsText');
        this.singleBookPriceTextElement			= $('singleBookPriceText');
        this.totalBookPriceTextElement			= $('totalBookPriceText');
        
        this.amountInputElement.observe('keyup', this.eventOnAmountKeyup.bind(this));
		this.previewLinkElement.observe('click', this.eventOnPreviewClick.bind(this));
		
        this.includeGuestbookContainerElement.hide();
        this.includeDigitalContainerElement.hide();
		this.discountContainerElement.hide();
		
        formHandler.options.onAmountInvalid = function() {
        	this.amountInputElement.style.border = '1px dotted red';
        }.bind(this);
        formHandler.options.onAmountValid = function() {
        	this.amountInputElement.style.border = '1px solid gray';
        }.bind(this);
        
    	ReisDagboek.Costs.AddObserver(this.eventOnPriceUpdate.bind(this));
	},
	
	/**
	 * Calculates and sets the total price.
	 */
	setTotalPrice: function() {
		
		if (!/^[1-9][0-9]*$/.test(this.amountInputElement.value)) {
			this.totalBookPriceTextElement.innerHTML = '0';
		} else {
			this.totalBookPriceTextElement.innerHTML = new Number(parseInt(this.amountInputElement.value) * this.price + 7).price(true);
		}
	},
	
	eventOnPreviewClick: function() {
		
		formHandler.submit('?action=preview', false, '_blank');
	},
	
	eventOnAmountKeyup: function() {
		
		if (/^[1-9][0-9]*$/.test(this.amountInputElement.value)) {
			ReisDagboek.Costs.Amount = parseInt(this.amountInputElement.value);
			ReisDagboek.Costs.Update();
		} else {
			this.totalBookPriceTextElement.innerHTML = '0';
		}
	},
    
    /**
     * Event is raised when the ajaxrequest for getting the amount of pages returned.
     */
    eventOnPriceUpdate: function(costs) {
		
		this.actualPagesTextElement.innerHTML = costs.ActualPages;
    	
		this.largebookCostsContainerElement[(costs.PartCount > 1) ? 'show' : 'hide']();
		this.bookPartCountElement.innerHTML = costs.PartCount;
		
		this.maxAmountElement.innerHTML = costs.MaxAmount;
		
		this.includeGuestbookContainerElement[(costs.IncludeGuestbook) ? 'show' : 'hide']();
		this.guestbookPriceTextElement.innerHTML = costs.GuestbookPrice.price(true);
		this.guestbookPagesTextElement.innerHTML = costs.GuestbookPages;
		
		this.includeDigitalContainerElement[(costs.IncludeDigitalFiles) ? 'show' : 'hide']();
		this.digitalPriceTextElement.innerHTML = costs.Digital.price(true);
		
		this.discountContainerElement[(costs.Discount) ? 'show' : 'hide']();
		this.discountTextElement.innerHTML = costs.Discount.price(true);
    	
    	this.pagesTextElement.innerHTML 			= costs.Pages_noGuestbook;
    	this.singleBookPriceTextElement.innerHTML 	= costs.Price_noGuestbook.price(true);
    	this.sendCostsTextElement.innerHTML 		= costs.ActualSendCosts.price(true);
    	this.totalBookPriceTextElement.innerHTML	= costs.ActualTotalPrice.price(true);
    }
});

/**
 * The contentcontainer for the layoutpage.
 */
ReisDagboek.ContentContainer.Layout = Class.create();
Object.extend(Class.Extend(ReisDagboek.ContentContainer, ReisDagboek.ContentContainer.Layout), {

    initialize: function(element, options) {
        
        this.initializeBase(element, options);
        
        this.indelingPremiumElement = $('indelingPremium');
        this.indelingBudgetElement  = $('indelingBudget');
        this.layoutElement          = $('layout');
        this.layoutContainerElement = $('layoutContainer');
        
        this.currentLayout          = $F('layout');
        
        this.indelingPremiumElement.observe('click', this.eventOnPremiumClick.bind(this));
        this.indelingBudgetElement.observe('click', this.eventOnBudgetClick.bind(this));
        
        this.loader = new ReisDagboek.Loader();
        
        ReisDagboek.Costs.AddObserver(this.eventOnPriceUpdate.bind(this));
	},
	
	eventOnPriceUpdate: function(costs) {

        this.loader.hide();
    	this.layoutElement.value = this.currentLayout;
	    
	},
    
    /**
     * Event is raised when the user selected the 'premium'-layout.
     */
    eventOnPremiumClick: function(response) {
    	
    	this.layoutElement.value = '';
    	this.currentLayout = 'premium';
        this.loader.show(this.layoutContainerElement);
    	
    	ReisDagboek.Costs.Receive();
    	
    },
    
    /**
     * Event is raised when the user selected the 'budget'-layout.
     */
    eventOnBudgetClick: function(response) {
    	
    	this.layoutElement.value = '';
    	this.currentLayout = 'budget';
        this.loader.show(this.layoutContainerElement);
    	
    	ReisDagboek.Costs.Receive(true);
    	
    }
});

/**
 * The contentcontainer for the paymentpage.
 */
ReisDagboek.ContentContainer.Payment = Class.create();
Object.extend(Class.Extend(ReisDagboek.ContentContainer, ReisDagboek.ContentContainer.Payment), {

    initialize: function(element, options) {
        
        this.initializeBase(element, options);
        
        this.loader = new ReisDagboek.Loader();
        
        this.bankSelectionElement = $('banks');
        this.bankSelectionElement.style.visibility = 'hidden';
	},
    
    /**
     * Event is raised when the container fully appeared.
     */
    eventOnAppeared: function() {
    	
        this.element.setStyle({
            height: 'auto'
        });
        
        if (!this.issuersReceived) {
        
	        this.loader.show(this.bankSelectionElement);
	        
        	new Ajax.Request('boek.php?action=getIssuerList', {
	    		onComplete: this.eventOnAjaxIssuersReceived.bind(this)
	    	});
	    	this.issuersReceived = true;
        }
    },
    
    /**
     * Event is raised when the issuerlist was received.
     */
    eventOnAjaxIssuersReceived: function(response) {
    	
    	var result = eval('('+response.responseText+')');
    	
    	if (!result.error) {
    		
    		var lng = result['long'];
    		var srt = result['short'];
    		
			this.bankSelectionElement.options.add(new Option('Kies uw bank...', ''));
			
    		if (lng.length != 0) {
	    			
				for (var key in lng) {
					this.bankSelectionElement.options.add(new Option(lng[key], key));
	    		}
    		}
    		if (lng.srt != 0) {
    			
	    		for (var key in srt) {
					this.bankSelectionElement.options.add(new Option(srt[key], key));
	    		}
    		}
    		
    	} else {
    		alert(result.error);
    	}
    	
    	this.loader.hide();
    	
    }
});

/**
 * The contentcontainer for the extra options.
 */
ReisDagboek.ContentContainer.Extra = Class.create();
Object.extend(Class.Extend(ReisDagboek.ContentContainer, ReisDagboek.ContentContainer.Extra), {

    initialize: function(element, options) {
        
    	this.initializeBase(element, options);
    	
    	this.extraTextContainerElement 	= $('extraTextContainer');
    	this.guestbookPriceElement 		= $('guestbookPrice');
    	this.dititalPriceElement 		= $('digitalPrice');
    	this.includeGuestbookElement 	= $('includeGuestbook');
    	this.includeDigitalFilesElement = $('includeDigitalFiles');
        
        this.includeGuestbookElement.observe('click', this.eventOnIncludeGuestbookClick.bind(this));
        this.includeDigitalFilesElement.observe('click', this.eventOnIncludeDigitalFilesClick.bind(this));
    	
    	ReisDagboek.Costs.AddObserver(this.eventOnPriceUpdate.bind(this));
	},
	
	/**
	 * Event is raised when the user clicked on the 'Include guestbook' option.
	 */
	eventOnIncludeGuestbookClick: function() {
		
		ReisDagboek.Costs.IncludeGuestbook = this.includeGuestbookElement.checked;
		ReisDagboek.Costs.Update();

		formHandler.processElement('amount', 2);
	},
	
	/**
	 * Event is raised when the user clicked on the 'Include digital files' option.
	 */
	eventOnIncludeDigitalFilesClick: function() {
		
		ReisDagboek.Costs.IncludeDigitalFiles = this.includeDigitalFilesElement.checked;
		ReisDagboek.Costs.Update();
	},
    
    /**
     * Event is raised when a priceupdate was received.
     */
    eventOnPriceUpdate: function(costs) {

    	this.dititalPriceElement.innerHTML = new Number(costs.Digital).price();
    	this.guestbookPriceElement.innerHTML = new Number(costs.Price - costs.Price_noGuestbook).price();
    }
});

/**
 * The contentcontainer for the finished-page.
 */
ReisDagboek.ContentContainer.Finished = Class.create();
Object.extend(Class.Extend(ReisDagboek.ContentContainer, ReisDagboek.ContentContainer.Finished), {

    initialize: function(element, options) {
        
    	this.initializeBase(element, options);
    	
    	this.statusResponseElement = $('statusResponse');
	},
    
    /**
     * Event is raised when the container fully appeared.
     */
    eventOnAppeared: function() {
    	
        this.element.setStyle({
            height: 'auto'
        });

        new Ajax.Request('boek.php?action=requestStatus&transactionID='+this.options.transactionID, {
    		onComplete: this.eventOnAjaxStatusReceived.bind(this)
    	});
    },
    
    /**
     * Event is raised when the issuerlist was received.
     */
    eventOnAjaxStatusReceived: function(response) {
    	
    	var result = eval('('+response.responseText+')');
    	
    	var message = result.error || 'De bestelling is voltooid. Het dagboek zal binnen 4 weken bezorgd worden. Bedankt voor de bestelling en we wensen je veel lees- en kijkplezier met het dagboek!';
    	this.statusResponseElement.innerHTML = message;
    }
});

/**
 * The contentcontainer for the costspage.
 */
ReisDagboek.ContentContainer.PersonalData = Class.create();
Object.extend(Class.Extend(ReisDagboek.ContentContainer, ReisDagboek.ContentContainer.PersonalData), {

    initialize: function(element, options) {
        
        this.initializeBase(element, options);
        
        this.fnameInputElement 			= $('fname');
        this.lnameInputElement 			= $('lname');
        this.addressInputElement 		= $('address');
        this.houseNumberInputElement 	= $('housenumber');
        this.pcodeInputElement 			= $('pcode');
        this.cityInputElement 			= $('city');
        this.emailInputElement 			= $('email');
        this.dAddress1InputElement		= $('dAddress_1');
        this.dAddress0InputElement		= $('dAddress_0');
        this.d_fnameInputElement 		= $('d_fname');
        this.d_lnameInputElement 		= $('d_lname');
        this.d_addressInputElement 		= $('d_address');
        this.d_houseNumberInputElement 	= $('d_housenumber');
        this.d_pcodeInputElement 		= $('d_pcode');
        this.d_cityInputElement 		= $('d_city');
        this.dAddressContainerElement	= $('dAddressContainer');
        this.showAgreementElement		= $('showAgreement');
        
        this.pagesTextElement 					= $('pagesText_2');
		this.includeGuestbookContainerElement 	= $('includeGuestbookContainer_2');
		this.guestbookPriceTextElement			= $('guestbookPriceText_2');
		this.guestbookPagesTextElement			= $('guestbookPagesText_2');
		this.includeDigitalContainerElement 	= $('includeDigitalContainer_2');
		this.digitalPriceTextElement			= $('digitalPriceText_2');
        this.discountContainerElement			= $('discountContainer_2');
        this.discountTextElement				= $('discountText_2');
        this.sendCostsTextElement 				= $('sendCostsText_2');
        this.singleBookPriceTextElement			= $('singleBookPriceText_2');
        this.totalBookPriceTextElement			= $('totalBookPriceText_2');
        
        this.dAddressContainerElement.hide();
        
        this.dAddress1InputElement.observe('click', this.eventOnDAddress1Click.bind(this));
        this.dAddress0InputElement.observe('click', this.eventOnDAddress0Click.bind(this));
        this.showAgreementElement.observe('click', this.eventOnShowAgreementClick.bind(this));
        
    	ReisDagboek.Costs.AddObserver(this.eventOnPriceUpdate.bind(this));
    	
        formHandler.options.onFnameInvalid = function() {
        	this.fnameInputElement.style.border = '1px dotted red';
        }.bind(this);
        formHandler.options.onFnameValid = function() {
        	this.fnameInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onLnameInvalid = function() {
        	this.lnameInputElement.style.border = '1px dotted red';
        }.bind(this);
        formHandler.options.onLnameValid = function() {
        	this.lnameInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onAddressInvalid = function() {
        	this.addressInputElement.style.border = '1px dotted red';
        }.bind(this);
        formHandler.options.onAddressValid = function() {
        	this.addressInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onHousenumberInvalid = function() {
        	this.houseNumberInputElement.style.border = '1px dotted red';
        }.bind(this);
        formHandler.options.onHousenumberValid = function() {
        	this.houseNumberInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onPcodeInvalid = function() {
        	this.pcodeInputElement.style.border = '1px dotted red';
        }.bind(this);
        formHandler.options.onPcodeValid = function() {
        	this.pcodeInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onCityInvalid = function() {
        	this.cityInputElement.style.border = '1px dotted red';
        }.bind(this);
        formHandler.options.onCityValid = function() {
        	this.cityInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onEmailInvalid = function() {
        	this.emailInputElement.style.border = '1px dotted red';
        }.bind(this);
        formHandler.options.onEmailValid = function() {
        	this.emailInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onD_fnameInvalid = function() {
        	if (this.dAddress1InputElement.checked) {
        		this.d_fnameInputElement.style.border = '1px dotted red';
        	}
        }.bind(this);
        formHandler.options.onD_fnameValid = function() {
        	this.d_fnameInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onD_lnameInvalid = function() {
        	if (this.dAddress1InputElement.checked) {
        		this.d_lnameInputElement.style.border = '1px dotted red';
        	}
        }.bind(this);
        formHandler.options.onD_lnameValid = function() {
        	this.d_lnameInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onD_addressInvalid = function() {
        	if (this.dAddress1InputElement.checked) {
        		this.d_addressInputElement.style.border = '1px dotted red';
        	}
        }.bind(this);
        formHandler.options.onD_addressValid = function() {
        	this.d_addressInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onD_housenumberInvalid = function() {
        	if (this.dAddress1InputElement.checked) {
        		this.d_houseNumberInputElement.style.border = '1px dotted red';
        	}
        }.bind(this);
        formHandler.options.onD_housenumberValid = function() {
        	this.d_houseNumberInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onD_pcodeInvalid = function() {
        	if (this.dAddress1InputElement.checked) {
        		this.d_pcodeInputElement.style.border = '1px dotted red';
        	}
        }.bind(this);
        formHandler.options.onD_pcodeValid = function() {
        	this.d_pcodeInputElement.style.border = '1px solid gray';
        }.bind(this);
        
        formHandler.options.onD_cityInvalid = function() {
        	if (this.dAddress1InputElement.checked) {
        		this.d_cityInputElement.style.border = '1px dotted red';
        	}
        }.bind(this);
        formHandler.options.onD_cityValid = function() {
        	this.d_cityInputElement.style.border = '1px solid gray';
        }.bind(this);
	},
    
    /**
     * Event is raised when the ajaxrequest for getting the amount of pages returned.
     */
    eventOnPriceUpdate: function(costs) {
		
		this.includeGuestbookContainerElement[(costs.IncludeGuestbook) ? 'show' : 'hide']();
		this.guestbookPriceTextElement.innerHTML = costs.GuestbookPrice.price(true);
		this.guestbookPagesTextElement.innerHTML = costs.GuestbookPages;
		
		this.includeDigitalContainerElement[(costs.IncludeDigitalFiles) ? 'show' : 'hide']();
		this.digitalPriceTextElement.innerHTML = costs.Digital.price(true);
		
		this.discountContainerElement[(costs.Discount) ? 'show' : 'hide']();
		this.discountTextElement.innerHTML = costs.Discount.price(true);
    	
    	this.pagesTextElement.innerHTML 			= costs.Pages_noGuestbook;
    	this.singleBookPriceTextElement.innerHTML 	= costs.Price_noGuestbook.price(true);
    	this.sendCostsTextElement.innerHTML 		= costs.ActualSendCosts.price(true);
    	this.totalBookPriceTextElement.innerHTML	= costs.ActualTotalPrice.price(true);
    },
	
	eventOnDAddress1Click: function() {
		
		if (this.dAddressContainerElement.visible()) {
			return;
		}
		
		this.dAddress1InputElement.disabled = true;
		this.dAddress0InputElement.disabled = true;
		
		new Effect.BlindDown(this.dAddressContainerElement, {
			afterFinish: this.eventOnDAddressContainerShown.bind(this),
			duration: 0.5
		});
	},
	
	eventOnDAddress0Click: function() {
		
		if (!this.dAddressContainerElement.visible()) {
			return;
		}
		
		this.dAddress1InputElement.disabled = true;
		this.dAddress0InputElement.disabled = true;
		
		new Effect.BlindUp(this.dAddressContainerElement, {
			afterFinish: this.eventOnDAddressContainerHidden.bind(this),
			duration: 0.5
		});
	},
	
	eventOnDAddressContainerShown: function() {

		this.dAddress1InputElement.disabled = false;
		this.dAddress0InputElement.disabled = false;
	},
	
	eventOnDAddressContainerHidden: function() {
		
		this.dAddress1InputElement.disabled = false;
		this.dAddress0InputElement.disabled = false;
	},
	
	eventOnShowAgreementClick: function() {
		new ReisDagboek.Window.Agreements();
	}
});

/**
 * A content container.
 */
ReisDagboek.ContentContainer.FirstPage = Class.create();
Object.extend(Class.Extend(ReisDagboek.ContentContainer, ReisDagboek.ContentContainer.FirstPage), {

    initialize: function(element, options) {
        
        this.initializeBase(element, options);
        
        this.textSelectOptionBlocks  = [];
        this.imageSelectOptionBlocks = [];
        
        $A(this.element.getElementsByClassName('optionBlock')).each(function(optionBlockElement, index) {
            
            if (optionBlockElement.hasClassName('image')) {           	
                this.initializeImageSelectButton(optionBlockElement, 'frontpageImage'+(this.imageSelectOptionBlocks.length + 1));
            }
            if (optionBlockElement.hasClassName('text')) {
        		
		        if (optionBlockElement.hasClassName('title')) {
		        	this.initializeTextSelectButton(optionBlockElement, 'title');
		       	} else if (optionBlockElement.hasClassName('subtitle')) {
		        	this.initializeTextSelectButton(optionBlockElement, 'subtitle');
		       	}
            }
            
        }.bind(this));
    },
    
    initializeTextSelectButton: function(optionBlockElement, name) {
        
        var optionBlock = new ReisDagboek.OptionBlock(optionBlockElement, {
            name: name,
            onButtonClick: function() {
                this.eventOnTextSelectClick(optionBlock);
            }.bind(this)
        });
        this.textSelectOptionBlocks.push(optionBlock);
    },
    
    initializeImageSelectButton: function(optionBlockElement, name) {
        
        var optionBlock = new ReisDagboek.OptionBlock(optionBlockElement, {
            name: name,
            onButtonClick: function() {
                this.eventOnImageSelectClick(optionBlock);
            }.bind(this)
        });
        this.imageSelectOptionBlocks.push(optionBlock);
    },
    
    /**
     * Event is raised when the button for selecting a text has been clicked.
     */
    eventOnTextSelectClick: function(optionBlock) {
        
        var backgroundColor, ttl, txt;
        
        if (optionBlock.name == 'title') {
        	backgroundColor = 'F2AE30';
        	ttl = 'Titel invullen';
        	txt = 'Vul hieronder de titel van het dagboek. Deze titel zal onderaan elke pagina worden weergegeven. Bijvoorbeeld: Jordy en Rob in Mexico';
       	} else if (optionBlock.name == 'subtitle') {
       		backgroundColor = 'E77235';
       		ttl = 'Subtitel invullen';
       		txt = 'Vul hieronder de subtitel van het dagboek. Deze komt alleen op de voorkant van het boek. Bijvoorbeeld: Reisverslag 2007';
       	} else {
       		return;
       	}
        
        this.textSelector = new ReisDagboek.Window.TextSelector({
        	title: ttl,
        	helpText: txt,
        	value: formHandler.getValue(optionBlock.name),
            onAccept: function(text) {
            	this.textSelector.btnAccept.disable(),
                new Ajax.Request('boek.php?action=createFrontpageText&text=' + escape(text) + '&backcolor=' + backgroundColor, {
                	onComplete: function(response) { this.eventOnAjaxTextImageComplete(response, optionBlock, text); }.bind(this)
                });
                return false;
            }.bind(this)
        });
    },
    
    /**
     * Event is raised when the ajaxrequest for setting a text has returned.
     */
    eventOnAjaxTextImageComplete: function(response, optionBlock, text) {
    
    	var result = eval('('+response.responseText+')');
    	
    	if (result.error) {
    		this.textSelector.btnAccept.enable();
    		alert(result.error);
    	} else if (result.file) {
    		
    		if (!optionBlock.textImageContainer) {
    			optionBlock.textImageContainer = document.createElement('IMG');
    			optionBlock.textImageContainer.style.margin = '10px';
    			optionBlock.element.appendChild(optionBlock.textImageContainer);
    		}
    		optionBlock.textImageContainer.src = result.file;

    		formHandler.setValue(optionBlock.name, text);
    		
            // the button automaticly hides
            optionBlock.autoHideButton(true);
    		
    		this.textSelector.close(true);
    	}
    },
    
    eventOnImageSelectClick: function(optionBlock) {
        
        var imageSelector = new ReisDagboek.Window.ImageSelector({
            onAccept: function(imageObject) {
                
                // the button automaticly hides
                optionBlock.autoHideButton(true);
                
                var cropWindow = new ReisDagboek.Window.ImageCropper(imageObject.full, {
                    previewElement: optionBlock.element,
                    
                    onAccept: function(coords) {
                        
    					formHandler.setValue(optionBlock.name, imageObject.full);
    					formHandler.setValue(optionBlock.name + 'Croparea', Hash.toQueryString(coords));
   						
                        optionBlock.hasImage = true;
                        
                    }.bind(this),
                    
                    onCancel: function() {
                        
                        cropWindow.cropObject.previewImg.remove();
                        
                        if (!optionBlock.hasImage) {
                            optionBlock.autoHideButton(false);
                        }
                    }
                });
            }
        });
    }
});

/**
 * An optionblock on the first page.
 */
ReisDagboek.OptionBlock = Class.create();
ReisDagboek.OptionBlock.prototype = {
    
    initialize: function(element, options) {
        
        this.options = {
            onButtonClick: function() {},
            hideButton: false,
            name: false
        };
        Object.extend(this.options, options || {});

        this.element        = $(element);
		this.name			= this.options.name;
        this.buttonElement  = new ReisDagboek.Button({
            element: $(this.element.getElementsByClassName('button')[0]),
            onClick: this.eventOnButtonClick.bind(this)
        });
        
        this.autoHideButton(this.options.hideButton);
        
        // attatch events
        Event.observe(this.element, 'mouseover', this.eventOnMouseOverBlock.bind(this));
        Event.observe(this.element, 'mouseout', this.eventOnMouseOutBlock.bind(this));
    },
    
    /**
     * Event raises when the button on the optionblock is clicked.
     */
    eventOnButtonClick: function() {
        this.options.onButtonClick();
    },
    
    /**
     * Event raises when the mouse is over the block.
     */
    eventOnMouseOverBlock: function() {
        
        if (this.hideButton) {
            this.buttonElement.show();
        }
    },
    
    /**
     * Event raises when the mouse leaves the block.
     */
    eventOnMouseOutBlock: function() {
        
        if (this.hideButton) {
            this.buttonElement.hide();
        }
    },
    
    /**
     * Set the auto-hide funtion of the button on or off. It will show when the mouse is over the
     * block and hide when it leaves the block.
     */
    autoHideButton: function(value) {
        
        if (this.hideButton == value) {
            return;
        }
        
        this.hideButton = value;
        
        if (this.hideButton) {
            this.buttonElement.hide();
        } else {
            this.buttonElement.show();
        }
    }
    
};

/**
 * An content container.
 */
ReisDagboek.Window = Class.create();
ReisDagboek.Window.prototype = {

    initialize: function(options) {
        
        this.options = {
            title: 'Popup',
            contentElement: null,
            content: null,
            top: 75,
            left: 180,
            width: 400,
            height: 300,
            minWidth: 300,
            minHeight: 200,
            maxWidth: false,
            maxHeight: false,
            resizable: true,
            acceptButton: true,
            acceptButtonValue: 'OK',
            acceptButtonOptions: {},
            onAccept: function() {},
            cancelButton: true,
            cancelButtonValue: 'Annuleren',
            cancelButtonOptions: {},
            onCancel: function() {},
            parentElement: document.body
        };
        Object.extend(this.options, options || {});
        
        window.RBWINDOW_STATE = {
            INITIALIZING: 'initializing',
            IDLE:         'idle',
            LOADING:      'loading',
            LOADED:       'loaded'
        };
        
        this.parentElement = $(this.options.parentElement);
        
        this.bodyWrapElement = $(document.createElement('DIV'));
        
        /** create DOM **/
        
        // create window element
        this.element = $(document.createElement('DIV'));
        this.element.className = 'window';
        this.element.setStyle({
            position: 'absolute',
            top: this.options.top+'px',
            left: this.options.left+'px',
            width: this.options.width+'px',
            height: this.options.height+'px',
            zIndex: 999
        });
        
        this.setState(RBWINDOW_STATE.INITIALIZING);
        
        // title element
        this.titleElement = $(document.createElement('DIV'));
        this.titleElement.className = 'title';
        
        // control box
        this.controlBoxElement = $(document.createElement('DIV'));
        this.controlBoxElement.className = 'controlBox';
        
        this.imgClose = $(document.createElement('IMG'));
        this.imgClose.src = '/images/boek/close.gif';
        
        this.controlBoxElement.appendChild(this.imgClose);
        
        var clear = document.createElement('DIV');
        clear.style.clear = 'both';
        
        this.titleElement.appendChild(this.controlBoxElement);
        this.titleElement.appendChild(document.createTextNode(this.options.title));
        this.titleElement.appendChild(clear);
        
        this.contentWrapElement = $(document.createElement('DIV'));
        this.contentWrapElement.className = 'contentWrap';
        
        // an element to be used for the content
        if (this.options.contentElement) {
            
            if (this.options.contentElement.offsetParent) {
                Element.remove(this.options.contentElement);
            }
            
            this.contentElement = $(this.options.contentElement);
            this.contentElement.addClassName('content');
            
        } else {
            
            // create object for content
            this.contentElement = $(document.createElement('DIV'));
            this.contentElement.className = 'content';

            this.contentElement.appendChild(document.createTextNode(this.options.content || ''));
        }
        
        this.contentWrapElement.appendChild(this.contentElement);
        
        this.footerElement = $(document.createElement('DIV'));
        this.footerElement.className = 'footer';
        
        this.buttonContainerElement = $(document.createElement('DIV'));
        this.buttonContainerElement.className = 'buttonContainer';
        
        if (this.options.acceptButton) {
            
            this.btnAccept = new ReisDagboek.Button(Object.extend(this.options.acceptButtonOptions, {
                value: this.options.acceptButtonValue,
                parent: false,
                onClick: this.eventOnAcceptButtonClick.bind(this)
            }));
            this.buttonContainerElement.appendChild(this.btnAccept.element);
        }
        if (this.options.cancelButton) {
            
            this.btnCancel = new ReisDagboek.Button(Object.extend(this.options.cancelButtonOptions, {
                value: this.options.cancelButtonValue,
                parent: false,
                onClick: this.eventOnCancelButtonClick.bind(this)
            }));
            this.buttonContainerElement.appendChild(this.btnCancel.element);
        }
        
        var clear = document.createElement('DIV');
        clear.style.clear = 'both';
        
        this.buttonContainerElement.appendChild(clear);
        
        var clear = document.createElement('DIV');
        clear.style.clear = 'both';
        
        this.footerElement.appendChild(this.buttonContainerElement);
        this.footerElement.appendChild(clear);
        
        this.bodyWrapElement.appendChild(this.titleElement);
        this.bodyWrapElement.appendChild(this.contentWrapElement);
        this.bodyWrapElement.appendChild(this.footerElement);
        this.element.appendChild(this.bodyWrapElement);
        
        // make it draggable
        new Draggable(this.element, {
            handle: this.titleElement,
            starteffect: false,
            endeffect: false,
            onEnd: this.eventOnDragEnd.bind(this)
        });
        
        this.parentElement.appendChild(this.element);
        
        // attatch events
        Event.observe(this.imgClose, 'mouseover', this.eventOnCloseMoverOver.bind(this));
        Event.observe(this.imgClose, 'mouseout', this.eventOnCloseMoverOut.bind(this));
        Event.observe(this.imgClose, 'click', this.eventOnCloseClick.bind(this));
        
        // handle options
        if (this.options.resizable) {
            this.makeResizable();
        }
        
        this.setState(RBWINDOW_STATE.IDLE);
        
        // trigger resize event
        this.eventOnResize();
        
        // can be set on a subclass
        if (this.setContent) {
            this.setContent();
        }
    },
    
    /**
     * Event is raised when the acceptbutton is clicked.
     */
    eventOnAcceptButtonClick: function() {
        this.options.onAccept();
    },
    
    /**
     * Event is raised when the cancelbutton is clicked.
     */
    eventOnCancelButtonClick: function() {
        
        var res = this.options.onCancel();
        if (typeof(res) != 'boolean' || res) {
            this.close();
        }
    },
    
    /**
     * Event is raised when the window is dropped after being dragged.
     */
    eventOnDragEnd: function() {
        
        if (this.element.offsetLeft < 0) {
            this.element.style.left = 0;
        }
        if (this.element.offsetTop < 0) {
            this.element.style.top = 0;
        }
    },
    
    /**
     * Event is raised when the mouse is over the close image.
     */
    eventOnCloseMoverOver: function() {
        this.imgClose.src = '/images/boek/close_over.gif';
    },
    
    /**
     * Event is raised when the mouse leaves the close image.
     */
    eventOnCloseMoverOut: function() {
        this.imgClose.src = '/images/boek/close.gif';
    },
    
    /**
     * Event is raised when the close image is clicked.
     */
    eventOnCloseClick: function() {
        this.close();
    },
    
    /**
     * Event is raised when the mouse presses the resize button.
     */
    eventOnResizeMouseDown: function(evt) {
        
        this.resizeClickLeft = parseInt(this.element.style.left.replace(/px/, ''));
        this.resizeClickTop  = parseInt(this.element.style.top.replace(/px/, ''));

        var resizeClickOffsetX = (this.resizeClickLeft + this.element.offsetWidth) - evt.clientX;
        var resizeClickOffsetY = (this.resizeClickTop + this.element.offsetHeight) - evt.clientY;

        this.resizeClickLeft -= resizeClickOffsetX;
        this.resizeClickTop -= resizeClickOffsetY;
        
        Event.observe(document, 'mousemove', this.mouseMoveEventHandler);
        Event.observe(document, 'mouseup', this.mouseUpEventHandler);
        
        this.resizing = true;
        
        Event.stop(evt);
    },
    
    /**
     * Event is raised when the mouse releases the resizebutton.
     */
    eventOnResizeMouseUp: function(evt) {
        
        Event.stopObserving(document, 'mousemove', this.mouseMoveEventHandler);
        Event.stopObserving(document, 'mouseup', this.mouseUpEventHandler);
        
        this.resizing = false;
    },
    
    /**
     * Event is raised when the window is being resized and the mouse is being released.
     */
    eventOnMouseUp: function(evt) {
        
        Event.stopObserving(document, 'mousemove', this.mouseMoveEventHandler);
        Event.stopObserving(document, 'mouseup', this.mouseUpEventHandler);
        
        this.resizing = false;
    },
    
    /**
     * Event is raised when the window is being resized and the mouse is being moved.
     */
    eventOnMouseMove: function(evt) {

        var width = evt.clientX - this.resizeClickLeft;
        var height = evt.clientY - this.resizeClickTop;
        
        this.resize(width, height);
        
        Event.stop(evt);
    },
    
    /**
     * Event is raised when the window resizes.
     */
    eventOnResize: function() {
        this.contentWrapElement.style.height = (this.element.offsetHeight - this.bodyWrapElement.offsetHeight - 2 + this.contentWrapElement.offsetHeight)+'px';
    },
    
    /**
     * Makes the window resizable.
     */
    makeResizable: function() {
        
        if (this.resizable) {
            return;
        }
        
        // create the element
        if (!this.resizeElement) {
            
            this.resizeElement = $(document.createElement('DIV'));
            this.resizeElement.setStyle({
                display: 'block',
                cursor: 'nw-resize',
                background: 'url(/images/boek/resize.gif) no-repeat',
                width: '12px',
                height: '12px',
                position: 'absolute',
                right: 0,
                bottom: 0
            });
            
            this.element.appendChild(this.resizeElement);
        }
        
        // this handler is set on the onclick of the resize
        this.mouseMoveEventHandler = this.eventOnMouseMove.bind(this);
        this.mouseUpEventHandler = this.eventOnMouseUp.bind(this);
        
        // attatch events
        Event.observe(this.resizeElement, 'mousedown', this.eventOnResizeMouseDown.bind(this));
        Event.observe(this.resizeElement, 'mouseup', this.eventOnResizeMouseUp.bind(this));
        
        this.element.addClassName('resizable');
        
        this.resizable = true;
    },
    
    /**
     * Adds an element to the content element.
     *
     * @param object element the element to be added
     * @param object insertBefore [optional] if given, the element is added before this element
     */
    addElement: function(element, insertBefore) {
        
        if (insertBefore) {
            this.contentElement.insertBefore(element, insertBefore);
        } else {
            this.contentElement.appendChild(element);
        }
    },
    
    /**
     * Resize the window.
     */
    resize: function(width, height) {
        
        if (width) {
            if (width < this.options.minWidth) {
                width = this.options.minWidth;
            } else if (this.options.maxWidth && width > this.options.maxWidth) {
                width = this.options.maxWidth;
            }
            this.element.style.width = width+'px';
        }
        if (height) {
            if (height < this.options.minHeight) {
                height = this.options.minHeight;
            } else if (this.options.maxHeight && height > this.options.maxHeight) {
                height = this.options.maxHeight;
            }
            this.element.style.height = height+'px';
        }

        this.eventOnResize();
    },
    
    /**
     * Sets the state of the popup.
     */
    setState: function(state) {
        
        if (this.state) {
            if (this.state == state) {
                return;
            }
            this.element.removeClassName(this.state);
        }
        
        this.element.addClassName(state);
        
        this.state = state;
    },
    
    /**
     * Closes the window.
     */
    close: function(preventEffect) {
        
        if (preventEffect) {
            this.element.remove();
        } else {
        
            Effect.BlindUp(this.element, {
                duration: 0.4,
                afterFinish: function() { this.close(true) }.bind(this)
            });
        }
    }
    
};

/**
 * The popup which allows the user to select one of ther pictures.
 */
ReisDagboek.Window.ImageSelector = Class.create();
Object.extend(Class.Extend(ReisDagboek.Window, ReisDagboek.Window.ImageSelector), {
    
    initialize: function(options) {
        
        options = Object.extend({
            title: 'Selecteer een afbeelding',
            width: 300,
            height: 200,
            acceptButtonOptions: {
                disabled: true
            }
        }, options || {});
        
        this.pictures = {};
        
        this.initializeBase(options);
    },
    
    /**
     * Handles the content to be added to the window.
     */
    setContent: function() {
        
        this.setState(RBWINDOW_STATE.INITIALIZING);
        
        this.element.addClassName('imageSelector');
        
        this.setState(RBWINDOW_STATE.LOADING);
        
        new Ajax.Request('boek.php?action=getPictures', {
            onComplete: this.ajaxeventOnPicturesReceived.bind(this)
        });
    },
    
    /**
     * Triggers the onAccept with the given pictureobject and closes the window after that.
     */
    setPicture: function(pictureObject) {
        
        var result = this.options.onAccept(pictureObject);
        
        // they may cancel the close
        if (typeof(result) != 'boolean' || result) {
            this.close(true);
        }
    },
    
    /**
     * Event is raised when the acceptbutton is clicked.
     */
    eventOnAcceptButtonClick: function() {
        
        if (this.selectedPictureObject) {
            this.setPicture(this.selectedPictureObject);
        }
    },
    
    /**
     * Event is raised when the ajaxresponse of getting the pictures is completed.
     *
     * @param object response
     */
    ajaxeventOnPicturesReceived: function(response) {
        
        var responsePictures = eval(response.responseText);
        
        // preload images
        responsePictures.each(function(picture) {
            new Image().src = 'uploads/'+picture;
        });
        
        this.setState(RBWINDOW_STATE.INITIALIZING);
        
        // container for the pictures
        this.picturesContainer = $(document.createElement('DT'));
        this.picturesContainer.className = 'picturesContainer';
        this.picturesContainer.style.display = 'block';
        
        this.addElement(this.picturesContainer);
        
        // add all the pictures
        responsePictures.each(function(picture) {
            this.addPicture(picture);
        }.bind(this));
        
        var clear = $(document.createElement('DIV'));
        clear.style.clear = 'both';
        
        this.addElement(clear);
        
        // attatch events
        Event.observe(this.contentWrapElement, 'click', this.eventOnBodyClick.bind(this), false);
        
        this.setState(RBWINDOW_STATE.IDLE);
		
		this.resize(570, 300);
    },
    
    /**
     * Event raises when the mouse enters a picturecontainer.
     */
    eventOnPictureContainerMouseOver: function(pictureObject) {
        
        if (this.selectedPictureObject == pictureObject) {
            return;
        }
        
        pictureObject.containerElement.addClassName('over');
    },
    
    /**
     * Event raises when the mouse leaves a picturecontainer.
     */
    eventOnPictureContainerMouseOut: function(pictureObject) {
        pictureObject.containerElement.removeClassName('over');
    },
    
    /**
     * Event raises when a picturecontainer is clicked.
     */
    eventOnPictureContainerClick: function(pictureObject) {
        
        if (this.selectedPictureObject == pictureObject) {
            return;
        }
        
        if (this.selectedPictureObject) {
            this.selectedPictureObject.containerElement.removeClassName('selected');
        }
        
        pictureObject.containerElement.addClassName('selected');
        
        this.btnAccept.enable();
        
        this.selectedPictureObject = pictureObject;
    },
    
    /**
     * Event raises when a picturecontainer is doubleclicked.
     */
    eventOnPictureContainerDoubleClick: function(pictureObject) {
        
        // on doubleclick, set the picture
        this.setPicture(pictureObject);
    },
    
    /**
     * Event raises when the body is clicked.
     */
    eventOnBodyClick: function(evt) {

        if (this.selectedPictureObject) {
            
            this.selectedPictureObject.containerElement.removeClassName('selected');
            this.selectedPictureObject = null;
            
            this.btnAccept.disable();
        }
    },
    
    /**
     * Adds a picture to the content.
     *
     * @param string picture the name of the image
     */
    addPicture: function(picture) {

        // image already added
        if (this.pictures[picture]) {
            return;
        }
        
        var pictureObject = {
            thumb: 'uploads/thumb_'+picture,
            full:  'uploads/'+picture
        };
        
        pictureObject.containerElement = $(document.createElement('DL'));
        pictureObject.containerElement.className = 'pictureContainer';
        pictureObject.containerElement.setStyle({
            width: '125px',
            height: '100px',
			overflow: 'hidden',
            textAlign: 'center',
            cssFloat: 'left'
        });
        
        pictureObject.imageElement = $(document.createElement('IMG'));
        pictureObject.imageElement.src = pictureObject.thumb;
        pictureObject.imageElement.style.marginTop = '10px';
        
        // attatch events
        Event.observe(pictureObject.containerElement, 'mouseover', function() { this.eventOnPictureContainerMouseOver(pictureObject); }.bind(this));
        Event.observe(pictureObject.containerElement, 'mouseout', function() { this.eventOnPictureContainerMouseOut(pictureObject); }.bind(this));
        Event.observe(pictureObject.containerElement, 'click', function(evt) { this.eventOnPictureContainerClick(pictureObject); Event.stop(evt); }.bind(this));
        Event.observe(pictureObject.containerElement, 'dblclick', function(evt) { this.eventOnPictureContainerDoubleClick(pictureObject); Event.stop(evt); }.bind(this));
        
        pictureObject.containerElement.appendChild(pictureObject.imageElement);
        
        // add the picture
        this.picturesContainer.appendChild(pictureObject.containerElement);
        
        this.pictures[picture] = pictureObject;
    }
});

/**
 * The popup which allows the user to select an text.
 */
ReisDagboek.Window.TextSelector = Class.create();
Object.extend(Class.Extend(ReisDagboek.Window, ReisDagboek.Window.TextSelector), {
    
    initialize: function(options) {
        
        options = Object.extend({
            title: 'Tekst selecteren',
            helpText: 'Vul hieronder de tekst in welke op het blok moet verschijnen',
            width: 380,
            height: 200,
            value: '',
            acceptButtonOptions: {
                disabled: true
            }
        }, options || {});
        
        this.initializeBase(options);
        
        if (this.options.value) {
        	this.inputElement.value = this.options.value;
       	}
        
        this.inputElement.focus();
    },
    
    /**
     * Event is raised when the acceptbutton is clicked.
     */
    eventOnAcceptButtonClick: function() {
        this.setText();
        return false;
    },
    
    /**
     * Event is raised when the text changed.
     */
    eventOnTextChanged: function() {
        
        if (this.inputElement.value.length == 0) {
            this.btnAccept.disable();
        } else {
            this.btnAccept.enable();
        }
    },
    
    /**
     * Handles the content to be added to the window.
     */
    setContent: function() {
        
        this.setState(RBWINDOW_STATE.INITIALIZING);
        
        this.addElement(Builder.node('p', this.options.helpText));
        
        this.inputElement = Builder.node('input', {type: 'text'})
        this.formElement = Builder.node('form', [
            Builder.node('p', [this.inputElement])
        ]);
        
        Event.observe(this.inputElement, 'keyup', this.eventOnTextChanged.bind(this));
        Event.observe(this.formElement, 'submit', function(evt) {
            
            this.setText();
            Event.stop(evt);
            
        }.bind(this));
        
        this.addElement(this.formElement);
        
        this.setState(RBWINDOW_STATE.IDLE);
    },
    
    /**
     * Sets the text and closes the window if everything is correct.
     */
    setText: function() {
        
        if (this.inputElement.value.length == 0) {
            return;
        }
        
        var result = this.options.onAccept(this.inputElement.value);
        
        // they may cancel the close
        if (typeof(result) != 'boolean' || result) {
            this.close(true);
        }
    }
});

/**
 * The popup which allows the user to crop a image.
 */
ReisDagboek.Window.ImageCropper = Class.create();
Object.extend(Class.Extend(ReisDagboek.Window, ReisDagboek.Window.ImageCropper), {
    
    initialize: function(imageURL, options) {
        
        options = Object.extend({
            title: 'Afbeelding bijsnijden',
            helpText: 'Hier kunt u uw afbeelding naar wens bijsnijden',
            width: 600,
            height: 400,
            previewElement: false,
            cropOptions: {
                ratioDim: {
					x: 630,
					y: 480
				},
				minWidth: 210,
				minHeight: 160,
				displayOnInit: true
            },
            acceptButtonOptions: {
                disabled: true
            }
        }, options || {});
        
        if (options.previewElement) {
            options.cropOptions.previewWrap = options.previewElement;
        }
        
        this.imageURL = imageURL;
        
        this.initializeBase(options);
    },
    
    /**
     * Event is raised when the acceptbutton is clicked.
     */
    eventOnAcceptButtonClick: function() {
        
        var result = this.options.onAccept(this.coords);
        
        // they may cancel the close
        if (typeof(result) != 'boolean' || result) {
            this.close(true);
        }
    },
    
    /**
     * Event is raised when the image is loaded.
     */
    eventOnImageLoaded: function() {
    	this.btnAccept.enable();
    },
    
    /**
     * Handles the content to be added to the window.
     */
    setContent: function() {
        
        this.element.addClassName('imageCropper');
        
        this.helptextElement = $(document.createElement('P'));
        this.helptextElement.appendChild(document.createTextNode(this.options.helpText));
        
        this.imageElement = $(document.createElement('IMG'));
    		
		this.addElement(this.helptextElement);
		this.addElement(this.imageElement);
		
        this.imageElement.observe('load', this.eventOnImageLoaded.bind(this));
        this.imageElement.src = this.imageURL;
    	
        this.cropObject = new Cropper.ImgWithPreview(this.imageElement, Object.extend(this.options.cropOptions, {
            onEndCrop: function(c) {
            	this.coords = c;
            }.bind(this)
        }));
    }
});

/**
 * The popup which shows the agreements.
 */
ReisDagboek.Window.Agreements = Class.create();
Object.extend(Class.Extend(ReisDagboek.Window, ReisDagboek.Window.Agreements), {
    
    initialize: function(options) {
        
        options = Object.extend({
            title: 'Algemene voorwaarden',
            width: 800,
            height: 500,
            cancelButton: false
        }, options || {});
        
        this.initializeBase(options);
    },
    
    /**
     * Event is raised when the acceptbutton is clicked.
     */
    eventOnAcceptButtonClick: function() {
        
        var result = this.options.onAccept(this.coords);
        
        // they may cancel the close
        if (typeof(result) != 'boolean' || result) {
            this.close(true);
        }
    },
    
    ajaxeventOnAgreementsComplete: function() {
    	this.setState(RBWINDOW_STATE.IDLE);
    },
    
    /**
     * Handles the content to be added to the window.
     */
    setContent: function() {
        
        this.setState(RBWINDOW_STATE.LOADING);
        
        this.element.addClassName('agreements');
        
        new Ajax.Updater(this.contentElement, 'boek.php?action=agreements', {
            onComplete: this.ajaxeventOnAgreementsComplete.bind(this)
        });
    }
});
