/*
Script: printmaster.js
  
Copyright:
  copyright (c) 2007 wollzelle GmbH, <http://www.wollzelle.com>

Group: printmaster
  collects generic widgets and functionality for the Printmaster application
*/



/*
Class: Sheets
  each time a request for a sheet completes, the Sheets object gets extended
  with all sheet specific properties it needs; extending happens in the response

Note:
  static class
*/

var Sheets = {};

/*
Class: Shelf
  collects functions for product container

Note:
  static class
*/

var Shelf = {

    /*
    Property: resize
    window.onresize callback which resizes the product shelf (div#container);
    checks for window dimensions, resizes the toolbox for window width < 970px
    */

    resize: function() {
        var dims = window.getSize();

        var headerHeight = $chk($('header')) ? $('header').getHeight() : 0;
        var toolboxHeight = $chk($('toolbox')) ? $('toolbox').getHeight() : 0;
        var masterDataHeight = $chk($('navigation_md')) ? ($('navigation_md').getHeight() + 4) : 0;
        var budgetsHeight = $chk($('budget_selector')) ? $('budget_selector').getHeight() : 0;
        var containerHeight = $chk($('cart-container')) ? $('cart-container').getHeight() : 0;

        var shelfHeight = dims.y - (headerHeight + toolboxHeight + budgetsHeight + masterDataHeight) - containerHeight;

        if ($chk($('container')) && shelfHeight >= 0)
            $('container').setStyle('height', shelfHeight);
        if ($chk($('masterDatacontainer')) && shelfHeight >= 0)
            $('masterDatacontainer').setStyle('height', shelfHeight);
    }
};


/*
Class: LiveSearch
  instantiates a Live search widget
*/

var LiveSearch = new Class({
  
  Implements: [Events, Options],
  
  options: {
    request: '',
    update: '',
		resetElement: 'search_reset_button', // Default ID for reset button		
		emptyString: null,
		exampleLinkId: 'search_example_link'
  },
  
  /*
  Property: initialize
    sets properties for a new live search widget
    
  Arguments:
    input - DOM id of an HTML input element
    options - optional, can contain the following properties:
      request - the URL to query
      update - the DOM id of an HTML element to update
  */
  
  initialize: function(input, options) {
    this.setOptions(options);
	var defaultEmptyText = Resources.Resource.global_insert_search_text;
	if(this.options.emptyString == null)
		this.options.emptyString = defaultEmptyText;
    this.input = $(input);
    this.form = this.input.getParent(); // Getting parent container
    this.resetButton = $(this.options.resetElement); // Getting reset button element
    this.exampleLink = $(this.options.exampleLinkId); // Getting example link element
    
    if(!this.input && !this.form)
      throw('Required input and form elements not found.');
    
    if(this.form.hasClass('pretty'))
      return false;
  
    new Observer(this.input, this.sendQuery.bindWithEvent(this));
    
    // Adding click obserber to reset button
    if(this.resetButton) this.resetButton.addEvent('click', this.reset.bindWithEvent(this));
    
    // Added click observer for example link
    if(this.exampleLink) this.exampleLink.addEvent('click', this.searchExampleText.bindWithEvent(this));
      
    this.decorate();
  },
  
  /*
  Property: sendQuery
    sends a request containing a search query; updates an element with search results
  */
  
  sendQuery: function() {
	var searchQuery = encodeURIComponent(this.input.value);
	if($('search').get('class') == "pretty empty") searchQuery = "";
    new Request.HTML({
      url: this.options.request,
      update: this.options.update,
      evalScripts: true
    }).post({ query: searchQuery });
  },

  empty: function() {
    // event.stop() from Mootools 1.11 doesn't work for some reason, using path by calling 2 separate methods
    this.input.value = '';
    this.leaveEditMode();
  },
  
  /*
  Property: reset
    resets the search;
  */

  reset: function(event) {
    // event.stop() from Mootools 1.11 doesn't work for some reason, using path by calling 2 separate methods
    event.stopPropagation();
    event.preventDefault();
    this.input.value = '';
    this.input.focus();
    this.sendQuery();
  },
  
  /*
  Property: decorate
    makes search field look pretty and attaches events
  */
  decorate: function(){
    var spanLeft = new Element('span', { 'class': 'left'});
    var spanRight = new Element('span', { 'class': 'right'});
    spanLeft.inject(this.form, 'top');
    spanRight.inject(this.form, 'bottom');
    this.form.addClass('pretty');
    
    this.leaveEditMode();
    
    this.input.addEvent('focus', this.enterEditMode.bindWithEvent(this));
    this.input.addEvent('blur', this.leaveEditMode.bindWithEvent(this));
    this.input.addEvent('keyup', this.toggleReset.bindWithEvent(this));
  },
  
  /*
  Property: enterEditMode
    fires when input recieves focus 
  */
  enterEditMode: function(){
    if(this.form.hasClass('empty')) {
      this.form.removeClass('empty');
      this.input.set({'value': ''});
      this.resetButton.addClass('active');
    }
  },
  
  /*
  Property: leaveEditMode
    fires when input looses focus
  */
  leaveEditMode: function(){
    if(this.input.get('value') == '' || this.input.get('value') == this.options.emptyString) {
      this.form.addClass('empty');
      this.input.set({'value': this.options.emptyString});
      this.resetButton.removeClass('active');
    }
  },
  
  /*
  Property: toggleReset
    toggles visibility of reset button accordingly to input value 
  */
  toggleReset: function(){
    if(this.input.get('value').length > 0)
      this.resetButton.addClass('active');
    else
      this.resetButton.removeClass('active');
  },
  
  /*
  Property: searchExampleText
    Gets text from link element, places it to the search field and initiates search query
  */
  searchExampleText: function(event){
    event.stop();
    event.target.blur();
    var query = this.exampleLink.get('text').stripScripts();
    this.input.focus();
    this.input.set('value', query);
    this.sendQuery();
  }
  
});


/*
Class: Messages
  collects functions to show different Notifications/Messages

Note:
  static class  
*/

var Messages = {
  
  /*
  Property: show
    animates the appearance of a message;
    sets text, styles, position of a message
  
  Arguments:
    type - the type of message, e.g. 'success', 'error', etc.
    text - the text of the message to be shown
    options - optional, an object which can contain a <position> property
      <position> can be 'centered', which centers the message absolutely to the page
      <element> - the element to append the message to
  */
  
  show: function(type, text, options) {
	this.blink = 0;	
	var dateCreation = new Date();
	dateCreation = dateCreation.getTime();
	//console.log("ms:" + dateCreation);
    var effectOptions = options ? options : { wait: 0 };
	var curInstance = $('modalMessage');
    if(curInstance != null) {
        $clear(this.showContinueHint);
        this.showContinueHint = null;
        curInstance.dispose();
	}
    var message = new Element('div', {
      'class': 'message',
	  'id': 'modalMessage'
    });
	
    options = $extend({
      element: document.body, 	// By default message will be injected into the BODY element
	  delay: 3000,				// By default the message will be shown for 3000ms
	  waitForClick: 0,			// By default the message will not wait for click
	  onClickFunction: null,	// the function to be called after click event	
      position: 'centered' 		// and it will be centered by default
    }, options);	
    	
	var message_graph = new Element('div', {
		'class': 'message_' + type
	});
	message.adopt(message_graph);		
		
	var message_text = new Element('div', {
		'class': 'message text'
	}).set('html', text);
	message.adopt(message_text);
	
	if(options.waitForClick != 0) {							
		var message_key_info = new Element('div', {
			'class': 'message_key_info',
			'id': 'message_key_info'		
		}).set('html', Resources.Resource.global_continue_mouse);
		message.adopt(message_key_info);	
	}
	    	
    if(options.position) {
      if(options.position == 'centered') {
        var windowdimensions = window.getInnerDimensions();
        message_graph.setStyles({
           position: 'absolute',
           top: windowdimensions.height/2-120,
           left: windowdimensions.width/2-125
        });       		
        message_text.setStyles({
           position: 'absolute',
           top: windowdimensions.height/2-120,
           left: windowdimensions.width/2-125
        });       
		if(options.waitForClick != 0) {
			message_key_info.setStyles({
			   position: 'absolute',
			   top: windowdimensions.height/2-120,
			   left: windowdimensions.width/2-125
			});       		
		}
      } else {
        message_graph.setStyles({
           position: 'absolute',
           top: options.position.top,
           left: options.position.left
        });	  
        message_text.setStyles({
           position: 'absolute',
           top: options.position.top,
           left: options.position.left
        });
		if(options.waitForClick != 0) {
			message_key_info.setStyles({
			   position: 'absolute',
			   top: options.position.top,
			   left: options.position.left
			});		
		}
      }
    }
    
    var messageOpacityEffect = new Fx.Tween(message, {
      duration: 400,
      onComplete: function() {
		message.destroy();
      }
    }).set('opacity', 0);
    
	delay = options.delay;	
	message.injectInside(options.element);
		
	(function() { message.setStyle('opacity', 1); }).delay(effectOptions.wait);
	
	if(options.waitForClick != 0) {
        this.showContinueHint = Messages.waitForMouse.periodical(500);
		document.onclick = function(e) {
			var dateCreated = new Date();
			dateCreated = dateCreated.getTime();
			//wait for min. 700 ms until hide is possible
			if((dateCreated - dateCreation) > 700) {
				(function() { messageOpacityEffect.start('opacity', 0); }).delay(10);
				document.onclick = null;
                $clear(this.showContinueHint);
				if(options.onClickFunction != null) {
					(function() { options.onClickFunction(); }).delay(10);
				}
			}
		}.bind(this)
	}
	else {
		(function() { messageOpacityEffect.start('opacity', 0); }).delay(delay);
	}
  },
  
  waitForMouse: function() {
	if(this.blink == 0) {
		this.blink = 1;
		$('message_key_info').setStyle("visibility", "hidden");
	}
	else {
		this.blink = 0;
		$('message_key_info').setStyle("visibility", "visible");
	}
  },
  
  /*
  Property: success
    shows a success message
  */
  success: function(text, options) {
    Messages.show('success', text, options);
  },
  
  /*
  Property: error
    show an error message
  */  
  error: function(text, options) {
    Messages.show('error', text, options);
  }
};

/*
Class: Scala
  instantiates a new Scala object;
*/

var Scala = new Class({
  
  /*
  Property: initialize
    initializes a Scala object; sticks a scala to the bottom of a slider
  
  Arguments:
    slider - a Slider() object
    div - the HTML DIV element the scala gets appended to
  */
  
  initialize: function(slider, div) {
    slider.options.values.each(function(unit, i) {
      var delta = slider.toPosition(slider.options.values[i]) + 7;
      var span = new Element('span', {'class':'tick', 'style': 'left:' + delta + 'px'});
      var label = new Element('a', {'href':'#', 'class':'unit', 'title': unit + ' stück wählen'}).set('html', '<span>' + unit + '</span>');
      label.addEvent('click', function(event){
        event.stop();
        slider.setCustom(unit);
      });
      span.adopt(label);
      div.adopt(span);
    });
  }
});

/*
Class: CustomScala
  instantiates a new Scala object;
*/

var DateScala = new Class({
  
  Implements: Options,
  
  options: {
    values: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
  },
  /*
  Property: initialize
    initializes a Scala object; sticks a scala to the bottom of a slider
  
  Arguments:
    slider - a Slider() object
    div - the HTML DIV element the scala gets appended to
  */
  
  initialize: function(slider, div, options) {
    this.setOptions(options);
    
    var interval = 1000*60*60*24*31; // ~ one month
    
    for(var delta = slider.options.start; delta < slider.options.end; delta+=interval) {
		//console.log(slider.options.start);
      var d = new Date();
      var prev_d = new Date();
      d.setTime(delta);
      prev_d.setTime(delta - interval);
      var month = this.options.values[d.getMonth()];
      var year = d.getFullYear();
      var prevYear = prev_d.getFullYear();
      var strYear = new String(year).substr(2,2); // convert year to string and get only 2 last chars
      
      var offset = slider.toPosition(delta) - 3;
      var span = new Element('span', {'class': (prevYear != year) ? 'tick highlight' : 'tick', 'style': 'left:' + offset + 'px'});
      var label = new Element('span', {'class': (prevYear != year) ? 'unit highlight' : 'unit'}).set('html', month + ((prevYear != year)? ' ' + strYear : '') );
      span.adopt(label);
      div.adopt(span);
    }
  }
});


/*
Class: CustomSliderValue
  instantiates a new Scala object;
*/

var CustomSliderValue = new Class({
  
  /*
  Property: initialize
    initializes a CustomerSliderValue object; sticks a customslidervalue right beside a slider
  
  Arguments:
    slider - a Slider() object
    inputfield - the HTML DIV element the CustomerSliderValue object gets appended to
  */
  
  initialize: function(slider, inputfield) {
    this.input = inputfield;
    this.slider = slider;
    
    inputfield.addEvents({
      'change': this.check.bindWithEvent(this),
      'blur': this.check.bindWithEvent(this),
      'focus':  function(){
                  this.input.select();
                }.bindWithEvent(this)
    });
  },
  
  check: function(){
    var customValue = parseInt(this.input.get('value'), 10);
    if (isNaN(customValue)) {
      ArticlesPopup.popup.shake();
      this.input.set('value', '');
      this.input.focus();
    } else
      this.slider.setCustom(customValue);
  }
});


/*
Class: BudgetSelector
  instantiates a budget selector widget
*/

var BudgetSelector = new Class({
  
  Implements: Options,
  
  options: {
    onToggle: $empty,
    onSelected: $empty,
    onReset: $empty,
    request: '',
    update: ''
  },
  /*
  Property: initialize
    constructs a budget selector widget; sets default options
  
  Arguments:
    budgetlist - the DOM id of the element which contains the budgets
    options - optional, an object which can contain the following properties:
      <onToggle> - callback function to be called when the budgetsBar is expanded or hidden.
      <onSelected> - callback function to be called when a budget gets chosen
      <request> - an URL to request to if a budget gets selected
      <update> - the DOM id of an HTML element to update if a tag gets selected and a request gets fired
  */
  
  initialize: function(budgetSelector, budgetsList, options) {
    this.budgetSelector = $(budgetSelector);
    this.budgetList = $(budgetsList);
    
    this.budgets = this.budgetList.getElements('div.budget');
    BudgetSelector.activeBudget = undefined;
    
    this.budgetResetter = $('budget_0');
    if ($chk(this.budgetResetter))
      this.budgetResetter.hide();
    
    this.budgetList.hide();
    
    this.setOptions(options);

    this.budgets.each(function(budget) {
      budget.addEvent('click', function() { this.toggleActive(budget); }.bind(this));
    }.bind(this));
  },
  
  /*
  Property: toggleActive
    toggles the state of a budget; can send a request; calls the <onSelected> callback
  
  Arguments:
    tag - the HTML element which fired the event
    
  Note:
    this method is bound to an event object, in this context <this> is the HTML element which fired the event
  */
  
  toggleActive: function(budget) {
    var txt1=budget.getElement('span.label_selected_budget').innerHTML;
    var txt2=budget.getElement('div.budget_info').innerHTML;
    this.budgetSelector.getElement('span.label_selected_budget').set('html', txt1);
    this.budgetSelector.getElement('div.budget_info').set('html', txt2);
    
    //this.slideFx.slideOut();
    if (this.options.request)
      this.respondToSelectedBudget(budget);
    // reshow previous selected budget
    if ($chk(BudgetSelector.activeBudget))
      BudgetSelector.activeBudget.setStyle("display","block");
    // set previous budget to the now selected budget
    BudgetSelector.activeBudget=budget;
    // hide selected budget from the list
    budget.setStyle("display","none");
    
    if ($chk(this.budgetResetter)) { // in case the budgetresetter is not present
      if (budget.id!="budget_0")
        this.budgetResetter.setStyle("display","block");
      else
        this.budgetResetter.setStyle("display","none");
    }
    
    this.budgetList.hide();
    
    this.options.onSelected();
  },
  
  /*
  Property: toggleBudgetList
    collapses/expands the budgetlist
  */
  
  toggleBudgetList: function() {
      // this.slideFx.toggle();
      this.budgetList.toggle();
      this.options.onToggle();
  },
  
  /*
  Property: respondToSelectedBudget
    sends a request containing all selected tags to a specified request URL;
    can update an HTML element if specified
  */
  
  respondToSelectedBudget: function(budget) {
     new Request.HTML({
       url: this.options.request,
       update: this.options.update,
       evalScripts: true
     }).send('budget='+budget.id);
  }
});

/*
Class: MediaUploader
  collects functions to work with a MediaUploader widget

Note:
  static class
*/

var MediaUploader = {
  
  /*
  Property: initialize
    sets initial states, registers events and defines event handlers
  */
  
  initialize: function() {
    this.types = ['photo', 'logo', 'background'];
    this.types.each(function(media) {
      $('map_'+media).addEvents({
        'click': function() { MediaUploader.selectMedia(media); },
        'mouseenter': function() { MediaUploader.onMouseEnter(media); },
        'mouseleave': function() { MediaUploader.onMouseLeave(media); }
      });
    });
  },
  
  /*
  Property: selectMedia
    scrolls a sheet locally, sets a local media object
  
  Arguments:
    media - a media type, e.g. 'photo'
  
  Note:
    event handler
  */
  
  selectMedia: function(media) {
    ProductsPopup.scrollToSheet('sheet_media', {
      data: { 'media': media }
    });
  },
  
  /*
  Property: onMouseEnter
    sets the className of an HTML element
    
  Arguments:
    media - a media type, e.g. 'photo'  
  
  Note:
    event handler
  */
  
  onMouseEnter: function(media) {
    $('map_'+media).getElement('div.actuator').addClass('over');
  },
  
  /*
  Property: onMouseLeave
    sets the className of an HTML element

  Arguments:
    media - a media type, e.g. 'photo'  
      
  Note:
    event handler
  */
  
  onMouseLeave: function(media) {
    $('map_'+media).getElement('div.actuator').removeClass('over');
  },
  
  /*
  Property: setMedia
    sets the background of an HTML element which represents a certain media
  
  Arguments:
    media - a media type, e.g. 'photo'
    source - the source to an image  
  */
  
  setMedia: function(media, source) {
    $('map_'+media).setStyle('background', 'url(' + source + ')');
    $('input_'+media).value = source;
  },
  
  /*
  Property: getQueryStringForMedia
    constructs a querystring out of input values for each media type
  */
  
  getQueryStringForMedia: function() {
    return this.types.map(function(media) {
      return media+'=' + escape($('input_'+media).value);
    }).join('&');
  }
};

/*
Class: Filter
  collects functions to interact with data filters
*/

var Filter = new Class({
  /*
  Property: initialize
    sets initial states for filters
  */

  initialize: function(element, url) {
    this.url = url;
    this.element = $(element);
	
    this.request = new Request.HTML({
      url: this.url, 
      update: this.element,
      evalScripts: true
    });
  },
  
  /*
  Property: filterByDateRange
    requests data from a specific time period; updated the history overview with the results
  
  Arguments:
    rawBeginDate - timestamp of the beginDate, in milliseconds
    rawEndDate - timestamp of the endDate, in milliseconds      
  */
  
  filterByDateRange: function(rawBeginDate, rawEndDate,query) {
    this.request.send('begin_date=' + rawBeginDate + '&end_date=' + rawEndDate+query);
  },
  
  /*
  Property: filterByDateRangeFromExactDate
    requests data from a specific time period; updated the history overview with the results
  
  Arguments:
    params - paramters for the request  
  */
  
  filterByDateRangeFromExactDate: function(params) {
    this.request.send(params);
  },
  
  /*
  Property: filterByDateRangeFromElements
    requests data from a specific time period using specified input fields; updated the history overview with the results
  
  Arguments:
    beginElement, endElement - IDs or Elements of appropriate inputs elements with specified dates
  */
  
  filterByDateRangeFromElements: function(beginElement, endElement) {
    var beginElement = $(beginElement);
    var endElement = $(endElement);
    
    var rawBeginDate = beginElement.get('value');
    var rawEndDate = endElement.get('value');
    
    this.request.send('begin_date=' + rawBeginDate + '&end_date=' + rawEndDate);
  }
});

window.addEvent('resize', Shelf.resize);
window.addEvent('domready', function() {
  (function() { Shelf.resize(); }).delay(100);
});

/* Tokens */
var tokens = [
  ['Josef Müller', 'Coffi GmbH', 'Hauptstraße 5', 'Wien'],
  ['Markus Simpler', 'Siemens', 'Siemensstraße 1', 'Wien'],
  ['Lars Mayer', 'Coffi GmbH', 'Hauptstraße 5', 'Wien'],
  ['Leopold Mayer', 'Coffi GmbH', 'Hauptstraße 5', 'Wien'],
  ['Marion Schmied', 'Coffi GmbH', 'Hauptstraße 5', 'Wien']
];
