if ( window['DOMParser'] == undefined && window.ActiveXObject ) {
	DOMParser = function() { };
	DOMParser.prototype.parseFromString = function( xmlString ) {
		var doc = new ActiveXObject('Microsoft.XMLDOM');
	    doc.async = 'false';
	    doc.loadXML( xmlString );
		return doc;
	};
}
var Data = {
	
	
	
};
function trace() {
	if ( window.cimd.global.debugMode == true ) 
	{
		var l = arguments.length;
		var innerTrace = function(text){
			if (console.log) {
				console.log(text);
			}
			else {
				if( opera.postError ) {
					opera.postError( text )
				} else {
					// write into the DOM
					var d=document.getElementById("debug");
					if( d ) {
						d.innerHTML += "<br/>"+text;
					}
				}
			}
		};
		if (l == 1) {
			innerTrace(arguments[0]);
		}
		else {
			var t = '';
			for (var i = 0; i < l; i++) {
				t += arguments[i] + ' ';
			}
			innerTrace(t);
		}
	}
};
var Cookies = {
	DAY : 24*60*60*1000,
	DOMAIN : "",//Global.DOMAIN,
	
	create:function( name, value, time ) {
		if ( time ) {
			var date = new Date();
			date.setTime( time );
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; path=/"; // DOMAIN
	},
	
	read:function(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	},
	
	erase:function (name) {
		Cookies.create(name,"",-1);
	},
	
	getExpirationTime:function( days ) {
		var date = new Date();
		return date.getTime() + days * Cookies.DAY;
	}
};
function Observer(){
    this._listeners = {};
};

Observer.prototype = {

    constructor: Observer,

    addListener: function(type, listener)
	{
        if (typeof this._listeners[type] == "undefined"){
            this._listeners[type] = [];
        }

        this._listeners[type].push(listener);
    },

    fire: function(event)
	{
		
        if (typeof event == "string"){
            event = { type: event };
        }
        if (!event.target){
            event.target = this;
        }

		trace('Observer','#fire', event.type );

        if (!event.type){  //falsy
            throw new Error("Event object missing 'type' property.");
        }

        if (this._listeners[event.type] instanceof Array){
            var listeners = this._listeners[event.type];
            for (var i=0, len=listeners.length; i < len; i++){
                listeners[i].call(this, event);
            }
        }
    },

    removeListener: function(type, listener)
	{
        if (this._listeners[type] instanceof Array){
            var listeners = this._listeners[type];
            for (var i=0, len=listeners.length; i < len; i++){
                if (listeners[i] === listener){
                    listeners.splice(i, 1);
                    break;
                }
            }
        }
    }
};
var Inheritance = {
	
	extend : function( subClass, superClass ) { 
		var F = function() {}; 
		F.prototype = superClass.prototype; 
		subClass.prototype = new F(); 
		subClass.prototype.constructor = subClass;
	}
	
};


Date.prototype.data = {
	monthes : new Array(
		"Janvier",
		"Février",
		"Mars",
		"Avril",
		"Mai",
		"Juin",
		"Juillet",
		"Août",
		"Septembre",
		"Octobre",
		"Novembre",
		"Décembre"
	),
	days : new Array(
		"Dimanche",
		"Lundi",
		"Mardi",
		"Mercredi",
		"Jeudi",
		"Vendredi",
		"Samedi"
	)
};
Date.prototype.prettyDate = function() {
	
	diff = (((new Date()).getTime() - this.getTime()) / 1000),
	day_diff = Math.floor( diff / 86400 );
	//trace( day_diff );
	//if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )
	if ( isNaN(day_diff) || day_diff < 0 )
		return '';
	
	return day_diff == 0 && (
		diff < 60 && "à l'instant" ||
		diff < 120 && "il y a 1 minute" ||
		diff < 3600 && "il y a " + Math.floor( diff / 60 ) + " minutes" ||
		diff < 7200 && "il y a 1 heure" ||
		diff < 86400 && "il y a " + Math.floor( diff / 3600 ) + " heures") ||
		day_diff == 1 && "Hier" ||
		day_diff < 7 && "il y a " + day_diff + " jours" ||
		// day_diff < 31 && "il y a " + Math.ceil( day_diff / 7 ) + " semaine" + ( ( Math.ceil( day_diff / 7 ) > 1 )?'s':'' );
		"il y a " + Math.ceil( day_diff / 7 ) + " semaine" + ( ( Math.ceil( day_diff / 7 ) > 1 )?'s':'' );	
};

Date.prototype.frenchFormat=function() {
	var d = this.data.days[ this.getDay() ].toLowerCase();
	var m = this.data.monthes[ this.getMonth() ].toLowerCase();
	var h = ( this.getHours() < 10 ) ? '0'+this.getHours() : this.getHours();
	var min = ( this.getMinutes() < 10 ) ? '0'+this.getMinutes() : this.getMinutes();  
	return 'le '+ d + ' ' + this.getDate() + ' ' 
			+ m + ' ' + this.getFullYear() 
			+ ' à ' + h + 'h' + min; 
};

Date.prototype.setPgSqlDate=function( pPgSqlDate ) {
	//trace( pPgSqlDate );
	var lRet;
	lSplit = pPgSqlDate.split(' ');
	lYearMonthDay = lSplit[0];
	lHourMinuteSecondMsecondOffset = lSplit[1];
	lSplit = lYearMonthDay.split('-');
	lYear = lSplit[0];
	lMonth = lSplit[1];
	lDay = lSplit[2];
	lSplit = lHourMinuteSecondMsecondOffset.split('+');
	lHourMinuteSecondMsecond = lSplit[0];
	lOffset = lSplit[1];
	lSplit = lHourMinuteSecondMsecond.split('.');
	lHourMinuteSecond = lSplit[0];
	lMsecond = lSplit[1];
	lSplit = lHourMinuteSecond.split(':');
	lHour = lSplit[0];
	lMinute = lSplit[1];
	lSecond = lSplit[2];

	//trace( lYear, lMonth-1, lDay, lHour, lMinute, lSecond, 0 );

	this.setFullYear( lYear );
	this.setMonth( lMonth-1 );
	this.setDate( lDay );
	this.setHours( lHour );
	this.setMinutes( lMinute );
	this.setSeconds( lSecond );
	this.setMilliseconds( 0 );
	
	//this.setDate(lYear, lMonth-1, lDay, lHour, lMinute, lSecond, 0);
};

Date.prototype.setTimestamp=function( timestamp, unit ) 
{
	unit = unit || 's';
	var r = 1;
	switch( unit ) {
		case 'ms':
			r = 1000;
			break;
		case 'ns':
			r = 1000000;
			break;
		case 's':
		default:
			r = 1;
			break;
	}
	trace(  Math.round( timestamp/r ) );
	this.setTime( Math.round( timestamp/r ) );
};

window.common={};
(function() {
	
	var Currency = {
	
		EUR : "EUR",
		USD : "USD",
		GBP : "GBP",
		points:"points",
		
		translated : 
		{
			"EUR"	:'euros',
			"USD"	:'dollars',
			"GBP"	:'livres',
			"points":'points'
		},
		
		getCurrencies : function() {
			// memoized
			if( !this.hasOwnProperty('_currencies') ) {
				var cur = new Array();
				for (var key in Currency) {
					if (typeof Currency[key] == 'string') {
						cur.push(key);
					}
				}
				this['_currencies'] = cur;
			}			
			return this['_currencies'];
		},
		
		test : function( testedCurrency ) {
			for( var key in Currency ) {
				if (typeof Currency[key] == 'string') {
					if (Currency[key] == testedCurrency) {
						return true;
					}
				}
			}
			return false;
		},
		
		getHTMLEntities : function( currency ) {
			switch( currency ) {
				case Currency.EUR:
					return " &euro;"
					break;			
				case Currency.GBP:
					return "&pound;";
					break;
				case Currency.USD:
					return "$";
					break;
				case Currency.points:
					return "pts";
					break;
			}
			return null;
		},
		
		formatValueForCurrency : function(value, currency) {
			switch( currency ) {
				case Currency.EUR:
					return value + " &euro;"
					break;			
					
				case Currency.GBP:
					return "&pound; " + value;
					break;
				
				case Currency.USD:
					return "$ " + value;
					break;
				
				case Currency.points:
					return value + " pts";
					break;
					
				default :
					throw "Invalid currency " + currency;
			}
			return null;
		}
	};
	
	window.common.currency = Currency;
	
})();
(function() {

	function HorizontalSlideView( parent ) 
	{
		this.viewportWidth = $(parent).width();
		//this.viewportWidth = this.viewportWidth || 970;
		this.$container=$('<div></div>').css({
			'width' : this.viewportWidth*3+'px',
			'position' : 'relative',
			'height' : '100%'
		});
		
		// create the previous, current and next panel:
		var i=3;
		while( i-- ) {
			this.$container.append(
				$('<div></div>')
					.attr('id', 'pane'+i)
					.addClass('slide-panel')
					.css({
						'width' : this.viewportWidth+'px',
						'position' : 'relative',
						'display' : 'inline-block',
						'height' : '100%'	
					})
			)
		}
		// add to the scene:
		$(parent).empty().append(this.$container);
	};
	
	HorizontalSlideView.prototype.showPreviousPane= function(animate,oncomplete) {
		goTo.call(this, 0, animate, oncomplete );
	};
	HorizontalSlideView.prototype.showCurrentPane = function(animate,oncomplete) {
		goTo.call(this, -this.viewportWidth, animate, oncomplete );
	};
	HorizontalSlideView.prototype.showNextPane = function(animate,oncomplete) {
		goTo.call(this, -this.viewportWidth*2, animate, oncomplete );
	};
	
	HorizontalSlideView.prototype.append = function( els, oncomplete ) {
		var s = this;
		var w = this.viewportWidth/2 - 8;
		addToPane.call( s,  $('#pane1') , w  , els );
		this.showCurrentPane( false, oncomplete );
	};
	
	HorizontalSlideView.prototype.getFirstPane = function() {
		return this.$container.find("div.slide-panel:first");
	};
	
	HorizontalSlideView.prototype.getLastPane = function() {
		return this.$container.find("div.slide-panel:last");
	};
	
	HorizontalSlideView.prototype.appendAfterAndSlide = function( els, oncomplete ) 
	{
		var s = this;
		var w = this.viewportWidth/2 - 8;
		
		var firstPane = this.getFirstPane();
		var lastPane = this.getLastPane();
		
		lastPane.find('li').empty();
		addToPane.call( s,  lastPane , w  , els );	
		this.showNextPane(true, function() {	
			firstPane.empty().after( lastPane );
			s.showCurrentPane(false, oncomplete );
		});
	};
	
	HorizontalSlideView.prototype.appendBeforeAndSlide = function( els, oncomplete ) 
	{
		var s = this;
		var w = this.viewportWidth/2 - 8;
		
		var firstPane = this.getFirstPane();
		var lastPane = this.getLastPane();
		// remove image empty information
		
		firstPane.find('information').each(function() {$(this).empty()});
		firstPane.find('img').remove();
		
		addToPane.call( s, firstPane , w  , els );
		this.showPreviousPane(true, function() {
			lastPane.empty().before( firstPane );
			s.showCurrentPane(false, oncomplete );
		});
	};
	
	function addToPane( pane, w, els ) {
		pane.empty();
		var ul = $('<ul></ul>');
		for( var i=0,len=els.length;i<len;i++){
			trace( els[i].$element );
			ul.append( $('<li></li>').css({
				'display':'inline-block',
				'width':w+'px'
			}).append( els[i].$element ) );
			
		}
		$(pane).append( ul );
	}
	
	function goTo( left, animate, oncomplete ) {
		animate = animate || false;
		if( animate == true ) {
			this.$container.animate(
				{'left' : left + 'px' }, 'slow' , oncomplete
			);
		} else {
			this.$container.css('left', left + 'px');
			if( oncomplete )
				oncomplete.call(this);	
		}
	};

	window.HorizontalSlideView = HorizontalSlideView;
})();
// jsr_class.js
//
// JSONscriptRequest -- a simple class for making HTTP requests
// using dynamically generated script tags and JSON
//
// Author: Jason Levitt
// Date: December 7th, 2005
//
// A SECURITY WARNING FROM DOUGLAS CROCKFORD:
// "The dynamic <script> tag hack suffers from a problem. It allows a page 
// to access data from any server in the web, which is really useful. 
// Unfortunately, the data is returned in the form of a script. That script 
// can deliver the data, but it runs with the same authority as scripts on 
// the base page, so it is able to steal cookies or misuse the authorization 
// of the user with the server. A rogue script can do destructive things to 
// the relationship between the user and the base server."
//
// So, be extremely cautious in your use of this script.
//
//
// Sample Usage:
//
// <script type="text/javascript" src="jsr_class.js"></script>
// 
// function callbackfunc(jsonData) {
//      alert('Latitude = ' + jsonData.ResultSet.Result[0].Latitude + 
//            '  Longitude = ' + jsonData.ResultSet.Result[0].Longitude);
//      aObj.removeScriptTag();
// }
//
// request = 'http://api.local.yahoo.com/MapsService/V1/geocode?appid=YahooDemo&
//            output=json&callback=callbackfunc&location=78704';
// aObj = new JSONscriptRequest(request);
// aObj.buildScriptTag();
// aObj.addScriptTag();
//
//


// Constructor -- pass a REST request URL to the constructor
//
function JSONscriptRequest(fullUrl) {
    // REST request path
    this.fullUrl = fullUrl; 
    // Keep IE from caching requests
    this.noCacheIE = '&noCacheIE=' + (new Date()).getTime();
    // Get the DOM location to put the script tag
    this.headLoc = document.getElementsByTagName("head").item(0);
    // Generate a unique script tag id
    this.scriptId = 'JscriptId' + JSONscriptRequest.scriptCounter++;
};

// Static script ID counter
JSONscriptRequest.scriptCounter = 1;

// buildScriptTag method
//
JSONscriptRequest.prototype.buildScriptTag = function () {

    // Create the script tag
    this.scriptObj = document.createElement("script");
    
    // Add script object attributes
    this.scriptObj.setAttribute("type", "text/javascript");
    this.scriptObj.setAttribute("charset", "utf-8");
    this.scriptObj.setAttribute("src", this.fullUrl + this.noCacheIE);
    this.scriptObj.setAttribute("id", this.scriptId);
};
 
// removeScriptTag method
// 
JSONscriptRequest.prototype.removeScriptTag = function () {
    // Destroy the script tag
    this.headLoc.removeChild(this.scriptObj);  
};

// addScriptTag method
//
JSONscriptRequest.prototype.addScriptTag = function () {
    // Create the script tag
    this.headLoc.appendChild(this.scriptObj);
};
function md5 ( str ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Webtoolkit.info (http://www.webtoolkit.info/)
    // + namespaced by: Michael White (http://getsprink.com)
    // +    tweaked by: Jack
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // -    depends on: utf8_encode
    // *     example 1: md5('Kevin van Zonneveld');
    // *     returns 1: '6e658d4bfcb59cc13f96c14450ac40b9'
 
    var xl;
 
    var rotateLeft = function(lValue, iShiftBits) {
        return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
    };
 
    var addUnsigned = function(lX,lY) {
        var lX4,lY4,lX8,lY8,lResult;
        lX8 = (lX & 0x80000000);
        lY8 = (lY & 0x80000000);
        lX4 = (lX & 0x40000000);
        lY4 = (lY & 0x40000000);
        lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
        if (lX4 & lY4) {
            return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        }
        if (lX4 | lY4) {
            if (lResult & 0x40000000) {
                return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
            } else {
                return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
            }
        } else {
            return (lResult ^ lX8 ^ lY8);
        }
    };
 
    var _F = function(x,y,z) { return (x & y) | ((~x) & z); };
    var _G = function(x,y,z) { return (x & z) | (y & (~z)); };
    var _H = function(x,y,z) { return (x ^ y ^ z); };
    var _I = function(x,y,z) { return (y ^ (x | (~z))); };
 
    var _FF = function(a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var _GG = function(a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var _HH = function(a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var _II = function(a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var convertToWordArray = function(str) {
        var lWordCount;
        var lMessageLength = str.length;
        var lNumberOfWords_temp1=lMessageLength + 8;
        var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
        var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
        var lWordArray=new Array(lNumberOfWords-1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while ( lByteCount < lMessageLength ) {
            lWordCount = (lByteCount-(lByteCount % 4))/4;
            lBytePosition = (lByteCount % 4)*8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount)<<lBytePosition));
            lByteCount++;
        }
        lWordCount = (lByteCount-(lByteCount % 4))/4;
        lBytePosition = (lByteCount % 4)*8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
        lWordArray[lNumberOfWords-2] = lMessageLength<<3;
        lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
        return lWordArray;
    };
 
    var wordToHex = function(lValue) {
        var wordToHexValue="",wordToHexValue_temp="",lByte,lCount;
        for (lCount = 0;lCount<=3;lCount++) {
            lByte = (lValue>>>(lCount*8)) & 255;
            wordToHexValue_temp = "0" + lByte.toString(16);
            wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length-2,2);
        }
        return wordToHexValue;
    };
 
    var x=[],
        k,AA,BB,CC,DD,a,b,c,d,
        S11=7, S12=12, S13=17, S14=22,
        S21=5, S22=9 , S23=14, S24=20,
        S31=4, S32=11, S33=16, S34=23,
        S41=6, S42=10, S43=15, S44=21;
 
//    str = this.utf8_encode(str);
    x = convertToWordArray(str);
    a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
    
    xl = x.length;
    for (k=0;k<xl;k+=16) {
        AA=a; BB=b; CC=c; DD=d;
        a=_FF(a,b,c,d,x[k+0], S11,0xD76AA478);
        d=_FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
        c=_FF(c,d,a,b,x[k+2], S13,0x242070DB);
        b=_FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
        a=_FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
        d=_FF(d,a,b,c,x[k+5], S12,0x4787C62A);
        c=_FF(c,d,a,b,x[k+6], S13,0xA8304613);
        b=_FF(b,c,d,a,x[k+7], S14,0xFD469501);
        a=_FF(a,b,c,d,x[k+8], S11,0x698098D8);
        d=_FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
        c=_FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
        b=_FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
        a=_FF(a,b,c,d,x[k+12],S11,0x6B901122);
        d=_FF(d,a,b,c,x[k+13],S12,0xFD987193);
        c=_FF(c,d,a,b,x[k+14],S13,0xA679438E);
        b=_FF(b,c,d,a,x[k+15],S14,0x49B40821);
        a=_GG(a,b,c,d,x[k+1], S21,0xF61E2562);
        d=_GG(d,a,b,c,x[k+6], S22,0xC040B340);
        c=_GG(c,d,a,b,x[k+11],S23,0x265E5A51);
        b=_GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
        a=_GG(a,b,c,d,x[k+5], S21,0xD62F105D);
        d=_GG(d,a,b,c,x[k+10],S22,0x2441453);
        c=_GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
        b=_GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
        a=_GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
        d=_GG(d,a,b,c,x[k+14],S22,0xC33707D6);
        c=_GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
        b=_GG(b,c,d,a,x[k+8], S24,0x455A14ED);
        a=_GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
        d=_GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
        c=_GG(c,d,a,b,x[k+7], S23,0x676F02D9);
        b=_GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
        a=_HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
        d=_HH(d,a,b,c,x[k+8], S32,0x8771F681);
        c=_HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
        b=_HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
        a=_HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
        d=_HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
        c=_HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
        b=_HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
        a=_HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
        d=_HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
        c=_HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
        b=_HH(b,c,d,a,x[k+6], S34,0x4881D05);
        a=_HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
        d=_HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
        c=_HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
        b=_HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
        a=_II(a,b,c,d,x[k+0], S41,0xF4292244);
        d=_II(d,a,b,c,x[k+7], S42,0x432AFF97);
        c=_II(c,d,a,b,x[k+14],S43,0xAB9423A7);
        b=_II(b,c,d,a,x[k+5], S44,0xFC93A039);
        a=_II(a,b,c,d,x[k+12],S41,0x655B59C3);
        d=_II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
        c=_II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
        b=_II(b,c,d,a,x[k+1], S44,0x85845DD1);
        a=_II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
        d=_II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
        c=_II(c,d,a,b,x[k+6], S43,0xA3014314);
        b=_II(b,c,d,a,x[k+13],S44,0x4E0811A1);
        a=_II(a,b,c,d,x[k+4], S41,0xF7537E82);
        d=_II(d,a,b,c,x[k+11],S42,0xBD3AF235);
        c=_II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
        b=_II(b,c,d,a,x[k+9], S44,0xEB86D391);
        a=addUnsigned(a,AA);
        b=addUnsigned(b,BB);
        c=addUnsigned(c,CC);
        d=addUnsigned(d,DD);
    }
 
    var temp = wordToHex(a)+wordToHex(b)+wordToHex(c)+wordToHex(d);
 
    return temp.toLowerCase();
}
// http://github.com/paularmstrong/LabelOver
(function($) {

    $.fn.labelover = function() {
        
        this.each( function() {
            var $this = $(this);
            
			$this.val(""); // reset form
            
			var $label = $this.prev('label').css( 'display',  'block' );
            
            $this.parent().addClass('labelover');
            
			$label.click(function() {
                 $this.focus();
            });
			
			
            $this.focus(function() {
                if($this.val() == '') {
                    $label.stop().animate({ opacity: 0.4 }, 200);
                }
            }).blur(function() {
                if($this.val() == '') {
                    $label.stop().css({ display: 'block' }).animate({ opacity: 1 }, 200);
                }
            }).keydown(function() {
                if($label.css('opacity')) {
                    $label.stop().animate({ opacity: 0 }, 200, function() { $label.css({ display: 'none' }); });
                }
            });
            
        });
        
    }
	    
})(jQuery);
/*!
 * jQuery xmlDOM Plugin v1.0
 * http://outwestmedia.com/jquery-plugins/xmldom/
 *
 * Released: 2009-04-06
 * Version: 1.0
 *
 * Copyright (c) 2009 Jonathan Sharp, Out West Media LLC.
 * Dual licensed under the MIT and GPL licenses.
 * http://docs.jquery.com/License
 */
(function($) {
	// IE DOMParser wrapper
	if ( window['DOMParser'] == undefined && window.ActiveXObject ) {
		DOMParser = function() { };
		DOMParser.prototype.parseFromString = function( xmlString ) {
			var doc = new ActiveXObject('Microsoft.XMLDOM');
	        doc.async = 'false';
	        doc.loadXML( xmlString );
			return doc;
		};
	}
	
	$.xmlDOM = function(xml, onErrorFn) {
		try {
			var xmlDoc 	= ( new DOMParser() ).parseFromString( xml, 'text/xml' );
			if ( $.isXMLDoc( xmlDoc ) ) {
				var err = $('parsererror', xmlDoc);
				if ( err.length == 1 ) {
					throw('Error: ' + $(xmlDoc).text() );
				}
			} else {
				throw('Unable to parse XML');
			}
		} catch( e ) {
			var msg = ( e.name == undefined ? e : e.name + ': ' + e.message );
			if ( $.isFunction( onErrorFn ) ) {
				onErrorFn( msg );
			} else {
				$(document).trigger('xmlParseError', [ msg ]);
			}
			return $([]);
		}
		return $( xmlDoc );
	};
})(jQuery);








/*
 ### jQuery XML to JSON Plugin v1.0 - 2008-07-01 ###
 * http://www.fyneworks.com/ - diego@fyneworks.com
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 ###
 Website: http://www.fyneworks.com/jquery/xml-to-json/
*//*
 # INSPIRED BY: http://www.terracoder.com/
           AND: http://www.thomasfrank.se/xml_to_json.html
											AND: http://www.kawa.net/works/js/xml/objtree-e.html
*//*
 This simple script converts XML (document of code) into a JSON object. It is the combination of 2
 'xml to json' great parsers (see below) which allows for both 'simple' and 'extended' parsing modes.
*/
// Avoid collisions
;if(window.jQuery) (function($){
 
 // Add function to jQuery namespace
 $.extend({
  
  // converts xml documents and xml text to json object
  xml2json: function(xml, extended) {
   if(!xml) return {}; // quick fail
   
   //### PARSER LIBRARY
   // Core function
   function parseXML(node, simple){
    if(!node) return null;
    var txt = '', obj = null, att = null;
    var nt = node.nodeType, nn = jsVar(node.localName || node.nodeName);
    var nv = node.text || node.nodeValue || '';
    /*DBG*/ //if(window.console) console.log(['x2j',nn,nt,nv.length+' bytes']);
    if(node.childNodes){
     if(node.childNodes.length>0){
      /*DBG*/ //if(window.console) console.log(['x2j',nn,'CHILDREN',node.childNodes]);
      $.each(node.childNodes, function(n,cn){
       var cnt = cn.nodeType, cnn = jsVar(cn.localName || cn.nodeName);
       var cnv = cn.text || cn.nodeValue || '';
       /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>a',cnn,cnt,cnv]);
       if(cnt == 8){
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>b',cnn,'COMMENT (ignore)']);
        return; // ignore comment node
       }
       else if(cnt == 3 || cnt == 4 || !cnn){
        // ignore white-space in between tags
        if(cnv.match(/^\s+$/)){
         /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>c',cnn,'WHITE-SPACE (ignore)']);
         return;
        };
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>d',cnn,'TEXT']);
        txt += cnv.replace(/^\s+/,'').replace(/\s+$/,'');
								// make sure we ditch trailing spaces from markup
       }
       else{
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>e',cnn,'OBJECT']);
        obj = obj || {};
        if(obj[cnn]){
         /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>f',cnn,'ARRAY']);
         if(!obj[cnn].length) obj[cnn] = myArr(obj[cnn]);
         obj[cnn][ obj[cnn].length ] = parseXML(cn, true/* simple */);
         obj[cnn].length = obj[cnn].length;
        }
        else{
         /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>g',cnn,'dig deeper...']);
         obj[cnn] = parseXML(cn);
        };
       };
      });
     };//node.childNodes.length>0
    };//node.childNodes
    if(node.attributes){
     if(node.attributes.length>0){
      /*DBG*/ //if(window.console) console.log(['x2j',nn,'ATTRIBUTES',node.attributes])
      att = {}; obj = obj || {};
      $.each(node.attributes, function(a,at){
       var atn = jsVar(at.name), atv = at.value;
       att[atn] = atv;
       if(obj[atn]){
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'ARRAY']);
        if(!obj[atn].length) obj[atn] = myArr(obj[atn]);//[ obj[ atn ] ];
        obj[atn][ obj[atn].length ] = atv;
        obj[atn].length = obj[atn].length;
       }
       else{
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'TEXT']);
        obj[atn] = atv;
       };
      });
      //obj['attributes'] = att;
     };//node.attributes.length>0
    };//node.attributes
    if(obj){
     obj = $.extend( (txt!='' ? new String(txt) : {}),/* {text:txt},*/ obj || {}/*, att || {}*/);
     txt = (obj.text) ? (typeof(obj.text)=='object' ? obj.text : [obj.text || '']).concat([txt]) : txt;
     if(txt) obj.text = txt;
     txt = '';
    };
    var out = obj || txt;
    //console.log([extended, simple, out]);
    if(extended){
     if(txt) out = {};//new String(out);
     txt = out.text || txt || '';
     if(txt) out.text = txt;
     if(!simple) out = myArr(out);
    };
    return out;
   };// parseXML
   // Core Function End
   // Utility functions
   var jsVar = function(s){ return String(s || '').replace(/-/g,"_"); };
   var isNum = function(s){ return (typeof s == "number") || String((s && typeof s == "string") ? s : '').test(/^((-)?([0-9]*)((\.{0,1})([0-9]+))?$)/); };
   var myArr = function(o){
    if(!o.length) o = [ o ]; o.length=o.length;
    // here is where you can attach additional functionality, such as searching and sorting...
    return o;
   };
   // Utility functions End
   //### PARSER LIBRARY END
   
   // Convert plain text to xml
   if(typeof xml=='string') xml = $.text2xml(xml);
   
   // Quick fail if not xml (or if this is a node)
   if(!xml.nodeType) return;
   if(xml.nodeType == 3 || xml.nodeType == 4) return xml.nodeValue;
   
   // Find xml root node
   var root = (xml.nodeType == 9) ? xml.documentElement : xml;
   
   // Convert xml to json
   var out = parseXML(root, true /* simple */);
   
   // Clean-up memory
   xml = null; root = null;
   
   // Send output
   return out;
  },
  
  // Convert text to XML DOM
  text2xml: function(str) {
   // NOTE: I'd like to use jQuery for this, but jQuery makes all tags uppercase
   //return $(xml)[0];
   var out;
   try{
    var xml = ($.browser.msie)?new ActiveXObject("Microsoft.XMLDOM"):new DOMParser();
    xml.async = false;
   }catch(e){ throw new Error("XML Parser could not be instantiated") };
   try{
    if($.browser.msie) out = (xml.loadXML(str))?xml:false;
    else out = xml.parseFromString(str, "text/xml");
   }catch(e){ throw new Error("Error parsing XML string") };
   return out;
  }
		
 }); // extend $

})(jQuery);
// http://www.adamcoulombe.info/lab/jquery/width-truncate/jquery.widthTruncate.js
(function($){
 $.fn.extend({
 
 	widthTruncate: function(options) {
		var defaults = {
			width: 'auto',
			after: '...'
		};
		
	  var options = $.extend(defaults, options);
	  
	  return this.each(function() {
	  if(options.width=='auto'){ truncateWidth=$(this).width()-8; }else{ truncateWidth = options.width}
			 if($(this).width()>truncateWidth){		 
			 var smaller_text = $(this).text();
			 $(this).html('<span id="truncateWrapper" style="display:inline;">'+options.after+'</div>');
			 		i=1;
			         while ($('#truncateWrapper').width() < truncateWidth) {
						$('#truncateWrapper').html(smaller_text.substr(0, i) + options.after);
						i++;
					}
					$(this).html($('#truncateWrapper').html());
			}
		
	  });
	  
	}

 });
})(jQuery);
window.cimd = {
	global : null,
	service : {},
	model : {},
	controller : {},
	view : {
		store : {},
		controller : {}
	}
};

// GLOBAL:
window.cimd.global = {
	debugMode : false,
	
	IMG_PATH :'/php/',
	
	CIMD_CONTROLLER : '/php/cimdController.php',
	//CIMD_CONTROLLER : '/public2/php/cimdController.php',
	
	AJAX_TIMEOUT : 4000,
	PAYPAL_CALL_TIMEOUT : 10000,
	SESSION_TIMEOUT : 3600,
	FEEDS_TIC : 10000,
	STRIP_ITEM_COUNT : 2,
	
	store : {
		preapproval : {
			MIN_AMOUNT : 4,//0.79,
			MAX_AMOUNT : 100,
			// TODO : value
			duration : {
				ONE_WEEK 		: '1week',
				ONE_MONTH 		: '1month',
				THREE_MONTHES 	: '3monthes',
				SIX_MONTHES 	: '6monthes'
			}		
		}

	},
	
	library : {
		type : {
			FULL : 'full',
			CENSORED : 'censored'
		}
	},
	
	connectionState : {
		
		CONNECTED 		: 0,
		CONNECTING 		: 1,
		DISCONNECTED 	: 2
		
	},
	customEvent : {
		connection : {	
			
			CONNECT : 'connection.connect',
			DISCONNECT : 'connection.disconnect',
			BAD_LOGIN : 'connection.badlogin',
			SESSION_EXPIRED : 'connection.sessionexpired'
		},
		
		user :  {
			CREATED : 'user.created'
		},
		
		// data stuff
		common : {
			
			COMPLETE : 'common.data.complete',
			UPDATE : 'common.data.updated',
			ERROR_LOADING_DATA : 'common.data.loadingerror'
		},
		
		store : {
			PAYMENT_ERROR : 'store.paymenterror',
			SUBSCRIPTION_ADDED : 'subscriptionadded',
			REQUEST_PREAPPROVED_PLAN : 'requestpreapprovedplan',
			ADD_SUBSCRIPTION_REQUEST : 'addsubscriptionrequest'
		},
		
		validator : {
			VALID : 'validator.valid',
			INVALID : 'validator.invalid'	
		},
		
		usercreation : {
			COMPLETE : 'user.create.complete',
			FAILED : 'user.create.failed'
		},
		
		actions : {
			LIBRARY_LOAD_REQUESTED 		: 'actions.libraryloadrequested',
			NEXT_STRIP_REQUESTED 		: 'actions.nextstriprequested',
			PREVIOUS_STRIP_REQUESTED 	: 'actions.previousstriprequested'
		},
		
		views : {
			REQUESTED_STRIP_COMPLETED : 'views.requestedstripcompleted',
			LIST_ITEM_CLICK	: 'listitemclick'
		}
	},
	
	subscription : {
		'UNLIMITED' : 1,
		'SCHUFFLE' : 2,
		'AUTHOR' : 3
	}
	
};
(function() {

	function CMUser( xmlData ) {
		this.linkedEmail = null;
		this.token = null;
		
		this.email = null;
		this.password=null;
		// fill data
		init.call( this, xmlData );
	};	

	function init( xmlData ) 
	{
		var d = $.xml2json(xmlData);
		this.token = d.session.id;
		this.linkedEmail = d.session.email;
	};

	window.cimd.model.User = CMUser;
})();
(function() {
	
	var LEN = 2;
	
	window.cimd.model.Library = function( xmlData ) {
		this.cartoons = null;
		
		this.it = 0;
		
		this.window = new Array(0,LEN);
		
		this.currentData=new Array();
		this.memento=new Array();
		init.call( this, xmlData );
	};
	
	window.cimd.model.Library.prototype.goTo = function( it ) {
		
		var it = it - it%LEN;
		trace( 'GOTO =', this.it , 'cartoon length', this.cartoons.length, it + LEN );
		// special case
		if( this.cartoons.length == 1 )  {
			this.it = 0;
			return true;
		} else		
		if( it + LEN <= this.cartoons.length  ) {
			this.it = it;
			return true;
		}	
		return false;	
	};
	
	/* Iterator handlers access */
	window.cimd.model.Library.prototype.current = function() {
		trace('CURRENT = ', this.it );
		var subData = new Array();
		for( var i=this.it;i<this.it+LEN;i++ ) {
			subData.push( this.cartoons[i] );
		}
		return subData;
	};
	
	window.cimd.model.Library.prototype.next = function() {
		trace( 'NEXT =', this.it );
		if( this.cartoons ) {
			if( this.it + LEN < this.cartoons.length ) {
				this.it+=LEN;
				return true;	
			}	
		}
		return false;	
	};
	
	window.cimd.model.Library.prototype.previous = function() {
		trace( 'PREVIOUS =', this.it );
		if( this.it-LEN >= 0 ) {
			this.it-= LEN;
			return true;	
		}
		return false;
	};
	
	function init( xmlData ) {
		var self = this;
		self.cartoons = new Array();
		var il = 0;
		$( xmlData ).find("cartoon").each(function() 
		{
		    var n = $(this);
			
			// CREATE THE CARTOON DATA
			var c = new window.cimd.model.Cartoon();
			c.id = n.attr('id');
			
			var d = new Date();
			d.setTimestamp( n.attr('publicationdate'), 'ns' );
			c.publicationDate = d.prettyDate();

			c.author 	= n.attr('authorname');
			c.title 	= n.attr('name');
			c.thumb 	=  window.cimd.service.media.getDataPathForId( n.attr('thumbid') );
			
			c.censored = ( n.attr('censored') ) ? true:false;
			
			n.find("media").each(function() {
				var m = $(this);//media
				c.media = window.cimd.service.media.getDataPathForId( m.attr('dataid') ); 
				c.position = ( m.attr('position') == '0' ) ? 'h' : 'v';
			});
			c.nuInList = il++;
			self.cartoons.push( c );
		});
	};
})();

window.cimd.model.Cartoon=function(){
	this.id;
	this.title;
	this.publicationDate;
	this.author;
	this.thumb;
	this.media;
	this.censored;
	this.position; // 'h' or 'v'
	// TODO complete
	//this.author;
	
};
(function() {

	/*
		<root>
			
			<subscriptions>
				<subscription id="1" eur="4.99" usd="5.99" gbp="3.49" type="UNLIMITED" enddate="1293836400000">
					<settings authorfiltered="" notify="1"/>
				</subscription>
			</subscriptions>
			
			<plans>
				<plan id="1" eur="4.99" usd="5.99" gbp="3.49" type="UNLIMITED"/>
				<plan id="3" eur="4.99" usd="5.99" gbp="3.49" type="AUTHOR" authors="9;10;3;2;8;12;15;5;14;13;4;6;7"/>
				<plan id="2" eur="4.99" usd="5.99" gbp="3.49" type="SHUFFLE"/>
			</plans>
			
		</root>
		
	*/
	window.cimd.model.Subscription = function() 
	{
		this.id=null;
		this.prices={};
		
		this.prices[window.common.currency.EUR]=null;
		this.prices[window.common.currency.USD]=null;
		this.prices[window.common.currency.GBP]=null;

		this.type=null;
		this.settings={};
		
		this.endDate=null;
	};
	
	window.cimd.model.AuthorSubscription = function() {
		cimd.model.Subscription.call(this);
		this.author={
			id : null,
			name : null,
			thumb : null
		};
	};
	Inheritance.extend(cimd.model.AuthorSubscription , cimd.model.Subscription);
	
	
	/*
	function init( xmlNode ) 
	{
		this.id = xmlNode.attr( 'id' );
		if( parseInt( this.id ) == cimd.global.subscription.AUTHOR ) {
			// retrieve the author id:
		}
		for( var cur in this.prices ) 
		{
			this.prices[ cur ] = window.common.currency.formatValueForCurrency(
				xmlNode.attr( cur.toString().toLowerCase() ), cur
			);
		}
		
		this.type = xmlNode.attr( 'type' );		
		if ( xmlNode.attr('enddate') ) 
		{
			var d = new Date();
			d.setTimestamp( xmlNode.attr('enddate') );
			this.endDate = d.getFullYear() + '-' + d.getMonth()+1 + '-' + d.getDate();
		}
	};
	*/

})();

(function() {
	
	function Author(id) 
	{
		this.id=null;
		this.name='';
		this.biography='';
		this.cartoonCount=0;
		this.thumb=null;
	};
	
	window.cimd.model.Author = Author;	
})();


(function() {
	
	function Category(id,title,thumb) 
	{
		this.id=id;
		this.title=title;
		this.thumb = thumb;
		this.cartoonCount = 0;
	};
	
	window.cimd.model.Category = Category;	
})();


(function() {
	cimd.model.SubscriptionFactory={
		
		getSubscriptionFromXmlNode : function( xmlNode ) 
		{
			var out = new Array();
			var typeId = xmlNode.attr( 'id' );
			if( parseInt( typeId ) == cimd.global.subscription.AUTHOR ) {
				
				// AuthorSubscription
				xmlNode.find('author').each(function() 
				{
					var n = $(this);
					var subscription = new cimd.model.AuthorSubscription();
					subscription.author.id = n.attr('id');
					subscription.author.name = n.attr('name');
					subscription.author.thumb = n.attr('thumb');
					_initSubscriptionWithXMLNode( subscription, xmlNode );
					out.push( subscription );
					
				});
				
				
				/*
				// Author plan from global plans
				if( xmlNode.attr('authors') ) {
					var authors = xmlNode.attr('authors').split(';'),
						name = null;
					for( var i=0,len=authors.length;i<len;i++ ) 
					{
						var subscription = new cimd.model.AuthorSubscription();
						subscription.author.id = authors[i]; 
						if(  cimd.controller.main.data() ) {
							subscription.author.name = cimd.controller.main.data().authors[ authors[i] ].name;
						}
						_initSubscriptionWithXMLNode( subscription, xmlNode );
						out.push( subscription );
					}
				} else {
				*/	
					// Author plan from own subscription
					var settings = xmlNode.find('settings');
					if( settings ) {
						var authorId = settings.attr('author');
						if( authorId ) {
							var subscription = new cimd.model.AuthorSubscription();
							subscription.author.id = authorId; 
							if( cimd.controller.main.data() ) {
								subscription.author.name = cimd.controller.main.data().authors[ authorId ].name;
								_initSubscriptionWithXMLNode( subscription, xmlNode );
								out.push( subscription );
							}
						}
					}
				//}

			} else {
				var subscription = new cimd.model.Subscription();
				_initSubscriptionWithXMLNode( subscription, xmlNode );
				out.push( subscription );
			}
			return out;
		} 
	};
	
	// fill basic fields from XML to the subscription object
	function _initSubscriptionWithXMLNode( subscription, xmlNode ) 
	{
		subscription.id = xmlNode.attr( 'id' );
		for( var cur in subscription.prices ) 
		{
			subscription.prices[ cur ] = window.common.currency.formatValueForCurrency(
				xmlNode.attr( cur.toString().toLowerCase() ), cur
			);
		}
		switch( xmlNode.attr( 'type' ) ) {
			case 'UNLIMITED':
				subscription.type = 'illimité';
				break;
			case 'SHUFFLE':
				subscription.type = 'aléatoire';
				break;
			case 'AUTHOR':
				subscription.type = 'AUTHOR';
				break;
			
			
		}
		 
		if ( xmlNode.attr('enddate') ) 
		{

			var d = new Date();
			d.setTimestamp( xmlNode.attr('enddate') );
			subscription.endDate = d.frenchFormat().replace('à 00h00','');
		}
	};
})();

(function() {
	
	function Feeds( limit ) {
		this.limit = limit;
		this._data = new Array();
	};
	
	Feeds.prototype.add = function( feeds ) {
		if (feeds) 
		{
			for (var i = 0, l = feeds.length; i < l; i++) {
				this._data.push( feeds[i] );
			}
			
			// ensure coherence, remove the extra feed
			l = this._data.length;
			if( l > this.limit ) {
				this._data.splice( this.limit, this._data.length-this.limit );	
			}
		}
	};
	
	window.cimd.model.Feeds = Feeds;
})();

(function() {
	
	function LocalData( xml ) 
	{
		this.authors=null;
		this.categories=null;
		this.cartoonsCount=0;
		init.call( this, xml );
	};

	function init( xml ) {
		if( xml ) {
			
			var id=null, 
				n = null, 
				thumb = null, 
				self = this;
			
			this.authors = {};
			this.categories = new Array();
			
			// CARTOONS count
			this.cartoonsCount = parseInt( $(xml).find('cartoons').attr('count') );
			
			// AUTHORS
			$(xml).find('author').each(
				function() {
				
					n = $(this);
					id = parseInt( n.attr('id') );
					var a = new cimd.model.Author(id);
					a.thumb = n.attr('dataid');
					a.name = n.attr('name');
					//a.name = $(this).attr('biography');
					a.cartoonCount = n.attr('cartooncount');
					
					self.authors[ id ] = a;	
				
				}
			);
			
			// CATEGORY
			$(xml).find('category').each(
				function() {
					
					n = $(this);
					id = parseInt( n.attr('id') );
					thumb = cimd.service.media.getDataPathForId( n.attr('thumbid') );
					var c = new cimd.model.Category( id, n.attr('name'), thumb );
					c.cartoonCount = n.attr('cartooncount');
					
					self.categories.push( c );	
					
				}
			);
		}
	};

	window.cimd.model.LocalData = LocalData;
})();

window.cimd.service.media = {
	
	getDataPathForId : function( id , mode ) {
		mode = mode || 'private';
		if (mode == 'private') {
			var sessionId = window.c.connectedUser.token;
			return window.cimd.global.IMG_PATH + id + '-' + sessionId + '.png';
		} 
		if (mode == 'public') {
			var salt = window.cimd.controller.main.salt;
			return window.cimd.global.IMG_PATH + 'th'+id+'-'+salt+'.png';
		}
		return null;
		// http://cimd.ave-comics.com/public/php/515-gtmybnucdr5hpo9g5cn2lrgmiwy26lxn.png	
	}
	
};
(function() {
	
	var MediaLoader = function( mediasPath ) {
		this.mediasPath = null;
		this.data = {};
		if( $.isArray(mediasPath) ) {
			this.mediasPath = mediasPath;
		} else {
			this.mediasPath = new Array();
		}
	};

	MediaLoader.prototype={
		add :function( path ) {
			this.mediasPath.push( path )
		},
		load : function( oncomplete, onfailed ) {
			var self = this;
			var len = this.mediasPath.length;
			$(this.mediasPath).each(
				function( len ) {
					var p = this.toString();
					// TODO create an hash function for key
					self.data[ p ] = new Image();
					self.data[ p ].onload = self.data[ p ].onerror = function() {
						trace( 'MediaLoader#load ' +this.src + ' loaded');
						len--;
						if( len == 0 ) {
							// stop all is loaded
							if( oncomplete ) {
								oncomplete.call( self );
							}
						}
					};
					self.data[ p ].src = p;
				}
			);
		}
	};
	
	window.cimd.service.MediaLoader = MediaLoader;
})();

/**
 * @author florian
 */
(function() {
	
	var COOKIE_KEY = 'cm-user';
	
	window.cimd.service.userManager = {
		// params:
		/*
			handlers={ 
				success
				error
			}	
			
		*/		
		autoConnect : function( handlers ) 
		{
			var userFromCookie = Cookies.read( COOKIE_KEY );
			trace( 'userManager#autoConnect - UserFromCookie: ' + userFromCookie );
			if ( userFromCookie ) 
			{
				var userData = jQuery.parseJSON( userFromCookie );
				this.connect( 
					userData.email, 
					userData.password,
					userData.rememberMe,
					handlers 
				);
			} else {
				if( handlers && handlers.hasOwnProperty( 'error' ) ) {
					handlers.error( 'connectionfailed' ); // connection failed
				}
			}
		},
		
		// password = md5(password)
		connect: function( email, password, rememberMe, handlers ) 
		{
			//rememberMe = rememberMe || false;
			timeout = ( rememberMe ) ? cimd.global.SESSION_TIMEOUT:0;
			cimd.ajaxHelper.send( this,{
				type: 'POST',
				url: cimd.global.CIMD_CONTROLLER,
				timeout : cimd.global.AJAX_TIMEOUT,
				data: {
					pattern: 'hello',
					whoami : 'WEB',
					supportid : 'web',
					email: email,
					rememberme:timeout,
					password: password
				},
				success: function( xmlData ) 
				{
					// check xmlData first
					var state = $( xmlData ).find("state");
					var errorCode = state.attr('error');
					if ( errorCode == null ) 
					{
						// create the user
						var user = new window.cimd.model.User(xmlData);
						user.email = email;	
						user.password = password;						
						//storeUserToCookie( user, rememberMe );

						if (handlers && handlers.hasOwnProperty('success')) {
							handlers.success(user);
						}
						
					} else {
						 // DEFAULT : connection failed
						errorType = 'connectionfailed';
						errorCode = parseInt(errorCode);
						if( !isNaN(errorCode) ) {
							// NO LINKAGE
							if( errorCode == 12 )  {
								errorType = 'usernotlinked';
							}
						}
						if( handlers && handlers.hasOwnProperty( 'error' ) ) {
							handlers.error( errorType );
						}
					}
				},
				error: function( objAJAXRequest, strError ) {
					if( handlers && handlers.hasOwnProperty( 'error' ) ) {
						handlers.error( strError ); // timeout
					}
					//window.cimd.service.userManager.user = null;
				},
				dataType: "xml"
			});
		},
		
		disconnect : function() {
			//Cookies.erase( COOKIE_KEY );
			
			cimd.ajaxHelper.send( this,{
				type: 'POST',
				url: cimd.global.CIMD_CONTROLLER,
				timeout : cimd.global.AJAX_TIMEOUT,
				data: {
					pattern: 'bye'
				},
				success: function( xmlData ) {
					// check xmlData first
					var state = $( xmlData ).find("state");
					var errorCode = state.attr('error');
					if ( errorCode == null ) 
					{
						// call the disconnect funtion
						// TODO Move to main controller
						window.location.href="";
					}
				},
				error: function( objAJAXRequest, strError ) {
					if( handlers && handlers.hasOwnProperty( 'error' ) ) {
						handlers.error( strError ); // timeout
					}
					//window.cimd.service.userManager.user = null;
				},
				dataType: "xml"
			});
		},
		
		
		
		createUser : function( email, password, handlers ) 
		{
			var s = this;
			$.ajax({
				type: 'POST',
				url: cimd.global.CIMD_CONTROLLER,
				timeout : cimd.global.AJAX_TIMEOUT,
				data: {
					pattern: 'createAccount',
					email : email,
					password : md5(password)
				},
				success: function( xmlData ) {
					// check xmlData first
					var state = $( xmlData ).find("state");
					var errorCode = state.attr('error');
					if ( errorCode == null ) 
					{
						var key = 'accountcreated';
						var id = state.attr('id');
						if( id == 1 ) {
							// user is a already set
							key = 'accountalreadyset';
							trace('CMUserManager#createUser = ' + key);
							
						}
						if( handlers && handlers.hasOwnProperty( 'complete' ) ) {
							handlers.complete( key );
						}
					} else {
						if( handlers && handlers.hasOwnProperty( 'error' ) ) {
							handlers.error( 'creationfailed' );
						}
					}
				},
				error: function( objAJAXRequest, strError ) {
					if( handlers && handlers.hasOwnProperty( 'error' ) ) {
						handlers.error( strError ); // timeout
					}
				},
				dataType: "xml"
			});
		}
	};
	
	function storeUserToCookie( user, rememberMe ) 
	{
		if( user ) 
		{
			// TODO move to cookies this kind of transformation
			
			var usrData = "{\"email\":\""+user.email+"\",\"password\":\""+user.password+"\",";
			usrData += "\"rememberMe\":\""+rememberMe+"\"}";
			trace( "storeUserToCookie# " + usrData );
			
			var expDate = null;
			trace( 'storeUserToCookie - ' + rememberMe  );
			if ( true == rememberMe) {
				expDate = Cookies.getExpirationTime(256);
			}
			
			Cookies.create( COOKIE_KEY, usrData, expDate );
		}
	}
	
	
})();
(function() {
	
	/*
		common.global.library.type.FULL
		common.global.library.type.CENSORED
	
	*/
	function LibraryManager( type ) {
		this._type = type || cimd.global.library.type.FULL;
		
		Observer.call(this);
	};
	Inheritance.extend( LibraryManager, Observer );

	LibraryManager.prototype.init = function( user, range ) 
	{
		if( range && range.hasOwnProperty('offset') && range.hasOwnProperty('limit') ) 
		{
			// construct data:
			var data = {
				pattern: 'getallforinit',
				token : user.token,
				limit : range.limit,
				offset : range.offset,
				type : 'web'
			};
			if( this._type == cimd.global.library.type.FULL ) {
				data['showcensored'] = 'true';
			} else {
				data['censoredonly'] = 'true';
			}
			
			var s = this;
			// RANGE
			cimd.ajaxHelper.send( this, {
				type: 'POST',
				url: cimd.global.CIMD_CONTROLLER,
				timeout : cimd.global.AJAX_TIMEOUT,
				data:data,
				success: function( xmlData ) {

					var lib = new window.cimd.model.Library( xmlData );
					// local data is global application data
					// it contains informations such as the author list...
					var localData = new window.cimd.model.LocalData( xmlData );
					
					var e = {
						type : cimd.global.customEvent.common.COMPLETE,
						action : 'init',
						data: {
							local: localData,
							library: lib
						}	
					};
					s.fire( e );
				},
				error: function(x,e) {
					s.fire( {
						type : cimd.global.customEvent.common.ERROR_LOADING_DATA,
						error : e
					});
					
				},
				dataType: "xml"
			});	
		}
	};

	LibraryManager.prototype.getAll = function( user, range ) 
	{
		if( range && range.hasOwnProperty('offset') && range.hasOwnProperty('limit') ) 
		{
			var self = this;
			// construct data:
			var data = {
				pattern: 'getcartoons',
				token : user.token,
				limit : range.limit,
				offset : range.offset,
				type : 'web'
			};
			if( this._type == cimd.global.library.type.FULL ) {
				data['showcensored'] = 'true';
			} else {
				data['censoredonly'] = 'true';
			}
			
			// RANGE
			cimd.ajaxHelper.send( this, {
				type: 'POST',
				url: cimd.global.CIMD_CONTROLLER,
				timeout : cimd.global.AJAX_TIMEOUT,
				data : data,
				success: function( xmlData ) {
					var lib = new window.cimd.model.Library( xmlData );
					var event = {
						type : cimd.global.customEvent.common.COMPLETE,
						action : 'getall',
						data: {
							library: lib
						}	
					};
					self.fire( event );
				},
				error: function(x,e) {
					self.fire( {
						type : cimd.global.customEvent.common.ERROR_LOADING_DATA,
						error : e
					});
				},
				dataType: "xml"
			});	
		}
	};
	
	window.cimd.service.LibraryManager = LibraryManager;

})();
(function() {
	function CMStore(){
		Observer.call(this);
	};
	Inheritance.extend( CMStore, Observer );
	CMStore.prototype.getSubscriptions = function( user ) 
	{
		var event = {
			action : 'getSubscriptions'
		};
		var self = this;
		cimd.ajaxHelper.send(this,{
			type: 'POST',
			url: cimd.global.CIMD_CONTROLLER,
			timeout : cimd.global.AJAX_TIMEOUT,
			data: {
				pattern: 'getsubscription',
				type : 'web',
				token : user.token
			},
			success: function( xmlData ) {

				var subscriptions = {
					personal 	: new Array(),
					available 	: new Array()
				} 
				
				// 'subscription' and available 'plan'
				$( xmlData ).find("subscription").each(
					function() {
						var subscriptionArray = cimd.model.SubscriptionFactory.getSubscriptionFromXmlNode( $(this) );
						subscriptions.personal = subscriptions.personal.concat( subscriptionArray );
					}
				);
				
				$( xmlData ).find("plan").each(
					function() {
						var subscriptionArray = cimd.model.SubscriptionFactory.getSubscriptionFromXmlNode( $(this) );
						subscriptions.available = subscriptions.available.concat( subscriptionArray );
					}
				);
				
				// fire an event
				event.type = cimd.global.customEvent.common.COMPLETE;
				event.data = subscriptions;
				self.fire(event);
				
			},
			error: function( jx, errorCode ) 
			{
				event.type = cimd.global.customEvent.common.ERROR_LOADING_DATA;
				event.error = errorCode;
				self.fire(event);
			},
			dataType: "xml"
		});
	};
	
	/* 
	 	subscription 	is type of window.cimd.model.Subscription
	 	
	 */
	CMStore.prototype.renewSubscription = function( user, subscription  ) 
	{
		var data = {
			subscriptionid : subscription.id
		};
		if( subscription.id == cimd.global.subscription.AUTHOR ) {
			// get back the author id:
			data.authorid = subscription.author.id;
		}
		this.addSubscription( user, data  );	
	};
	
	/* 
	 	subscriptionData, fake subscription object
		{
			id : 3,
			extra : 1 // Author id
		}
	
	*/
	CMStore.prototype.addSubscription = function( user, subscriptionData  ) 
	{
		var event = {
			action : 'addSubscription'
		};
		
		var self = this;
		subscriptionData = jQuery.extend(
			subscriptionData,
			{
				'pattern' : 'addsubscription',
				'token' : user.token,
				'from': Math.floor( Math.random()*1000000000 ),
				'receipt' : 'website', // TODO put preapproval key
				'appid' : '100'
			}
		);
		
		// cause a paypal call the request could be have a long duration
		var timeout = cimd.global.PAYPAL_CALL_TIMEOUT;
		$.ajax({
			type: 'POST',
			url: cimd.global.CIMD_CONTROLLER,
			timeout: timeout,
			data: subscriptionData,
			success: function(xmlData) {
				// check errors ( cf cmidController.php )
				// 	define( 'BADRECEIPT', 		10 );
				//	define( 'WRONGSUBSCRIPTION',11 );
				//	define( 'NOLINKAGE',		12 );
				// 	define( 'NOPREAPPROVED', 	13 );
				
				// state id="0"
				var state = $(xmlData).find('state');
				if( state ) 
				{
					var id = state.attr('id');
					if ( id && parseInt(id) == 0 ) {
						// OK
						// self.getSubscriptions( user );	
						self.fire({
							type : 'subscriptionadded',
							data : subscriptionData
						});
					}
					else {
						var error = state.attr('error');
						if (error) 
						{
							var ecode = parseInt( error );
							if ( !isNaN(ecode) ) {
								switch( ecode ) {
									case 11:
										event.error = 'unavailableproduct';
																				
										break;
									case 13:
										// display the panel that display the preaproval...
									//	event.type = cimd.global.customEvent.common.COMPLETE;
									//	self.fire( event );
									
										event.error = 'obsoletepreapproval';
										break;
									case 14:
									
										event.error = 'preapprovalexpiration';	
										break;
									case 10:
										event.error = 'badreceipt';
									
										trace('#addSubscription bad receipt');
										break;
									case 15:
										event.error = 'amountlimit';
										
										trace('#addSubscription PREAPPROVALAMOUNTLIMIT' );
										break;
									case 16:
										event.error = 'failedtransaction';
										
										trace('#addSubscription TRANSACTIONHASFAILED');
										break;
									default:
										event.error = 'undefined';
										
										trace('#addSubscription ERROR n°'+ecode+' not implemented');
										break;
								}
								
							}
							else {
								// undefined error
								event.type = cimd.global.customEvent.common.ERROR_LOADING_DATA;
							}
						}
						
						//event.type = cimd.global.customEvent.common.ERROR_LOADING_DATA;
						event.type = cimd.global.customEvent.store.PAYMENT_ERROR;
					}
				} else {
					// undefined error
					event.type = cimd.global.customEvent.common.ERROR_LOADING_DATA;
				}
				self.fire( event );
			},
			error: function( jx, errorCode ) 
			{
				// TODO timeout
				event.type = cimd.global.customEvent.common.ERROR_LOADING_DATA;
				event.error = errorCode;
				self.fire( event );
			},
			dataType: "xml"
		});
	};
	window.cimd.service.StoreManager = CMStore;
	
})();
(function() {
	function CMPaymentManager( callbackUrl ) {
		// onsuccess, onerror
		this.callbackUrl = callbackUrl;
		Observer.call(this);
	};
	Inheritance.extend( CMPaymentManager, Observer );
	
	/*
	 * @data 	object {} with att: 'currency', 'endingdate', 'maxtotalamountofallpayments' 
	 */
	CMPaymentManager.prototype.requestPreapproval = function( user, data ) {
		var self = this;
		// compute data
		data = jQuery.extend(data, 
		 	{
				pattern: 'preapprovedme',
				token : user.token,
				appid : '100'
			}
		);
		// returned url:
		if( this.callbackUrl ) {
			data = jQuery.extend( 
				data, this.callbackUrl 
			);
		}
		
		$.ajax({
			type: 'POST',
			url: cimd.global.CIMD_CONTROLLER,
			timeout : cimd.global.AJAX_TIMEOUT,
			data: data,
			success: function( xmlData ) {
				// get back 
				var url = $(xmlData).find('url');
				if( url && url.text() ) {
					window.location.href = url.text();// GET call to paypal
				} else {
					// Error retrieving data
					self.fire(
						cimd.global.customEvent.common.ERROR_LOADING_DATA
					);
				}
				
				
				/*
				self.fire({
					type : cimd.global.customEvent.common.COMPLETE,
				});
				*/
			},
			error: function() {
				/// TODO timeout manage.
				self.fire(
					cimd.global.customEvent.common.ERROR_LOADING_DATA
				);
				
			}
		});
	};	
	
	window.cimd.service.PaymentManager = CMPaymentManager;
	
})();
(function(){
	/*
	 * SINGLETON
	 */
	var EMAIL_PATTERN = /^[a-z0-9._-]+@([a-z0-9_-]+.)+[a-z]{2,6}$/i;
	var events = cimd.global.customEvent.validator;
	
	function FieldsValidator() {
		Observer.call(this);
	};
	Inheritance.extend( FieldsValidator, Observer );
	
	FieldsValidator.prototype.check = function( form ) { 
		var s = this;
		var data={};
		var isallok = true;
		var inputs = $( form ).find(':input');
		inputs.each( function() 
		{
			$this = $(this);
			var type = $this.attr('type');
			if( type ) {
			
				type = type.toLowerCase();
				var et = null;
				if( type != 'hidden' && type != 'button' ) {
					
					et = events.INVALID;
					if ( checkField($this) ) 
					{
						et = events.VALID;
						// Store result to data
						switch (type) {
							case 'text':
							case 'password':
								data[$this.attr('name')] = $this.val();
								break;
							case 'checkbox':
								data[$this.attr('name')] = $this.is(':checked');
								break;
							case 'radio':
								if ($this.is(':checked')) {
									data[$this.attr('name')] = $this.val();
								}
								break;
						}
					} else {
						isallok = false;
					}
					
					// Fire event
					s.fire({
						type : et,
						data :$this
					});
				}
			}
		});

		return ( isallok ) ? data : null;
	};
	
	
	function checkField( $el )
	{
		
		var v = $el.val(), isEmpty = (jQuery.trim(v) == '');
		trace( 'CHECK: ' + $el.attr('name') + ' ' + $el.val() );
		switch ($el.attr('name') ) {
			case 'password':
				this._passValue = v;
				if (isEmpty) {
					return false;
				}
				break;
			case 'passwordRetype':
				// TODO check with password				
				if (isEmpty || v != this._passValue) {
					return false;
				}
				break;
			case 'email':
				
				if (isEmpty) {
					return false;
				}
				else {
					if (!EMAIL_PATTERN.test(v)) {
						return false;
					}
				}
				break;
			case 'nickname':
				if (isEmpty) {
					//return false;
					// TODO user
					// check nickname
					return false;
				}
				break;
			case 'pseudo':
				if (isEmpty) {
					return false;
				}
				break;
			case 'agree': // conditions générales
				if ($el.is(':checked') != true) {
					//inputEl.parentNode.className = "missingAgree";
					return false;
				}
				else {
				//inputEl.parentNode.className = "";
				}
				break;
			case 'message':
				if (!isEmpty || v.length > 300) {
					return false;
				}
				break;
		}
		trace( true );
		return true;
	}
	
	// SINGLETON
	window.cimd.service.fieldsValidator = new FieldsValidator();
})();
(function() {

	// wrapper for $.ajax jQuery caller
	// manage common errors
	var CMAjaxHelper = function() {
		Observer.call(this);
	};
	Inheritance.extend( CMAjaxHelper, Observer );
	
	CMAjaxHelper.prototype.send = function( context, params ) {
		var s = this;
		$.ajax( {
			type: params.type || 'POST',
			url: params.url || cimd.global.CIMD_CONTROLLER,
			timeout : params.timeout || cimd.global.AJAX_TIMEOUT,
			data:params.data || null,
			success : function( xmlData ) 
			{
				var event = null;
				var state = $( xmlData ).find("state");
				var errorCode = state.attr('error');
				if ( errorCode != null ) 
				{
					trace( 'ERROR: ' + errorCode );
					// TODO : popular with common errors:
					event = {
						type : cimd.global.customEvent.common.ERROR_LOADING_DATA
					};
					if( errorCode == 5 ) {
						event.error = 'sessionExpired'
					} 
					if( errorCode == 7 ) {
						event.error = 'connectionfailed'
					}
					if( errorCode == 12 )  {
						event.error  = 'usernotlinked';
					}
					
					s.fire( event );
			
					if( params.hasOwnProperty('error') ) {
						// TODO
						var x = null;
						var e = event.error || 'undefinederror';
						params.error.apply( this, [x, e] );
					}
					
				} else {
					if( params.hasOwnProperty('success') ) {
						params.success.call( this, xmlData ); // reinject data
					}
				}
			},
			error : params.error,
			dataType : params.dataType || 'xml'	
		});
	
	};
	
	window.cimd.ajaxHelper = new CMAjaxHelper();
})();
/*
 * Connection panel
 */
(function() {
	
	var containerId = 'cm-userPanel';
	
	cimd.view.controller.userPanelController = {
		
		init : function() 
		{
			var self = this;
			cimd.controller.main.addListener( cimd.global.customEvent.connection.CONNECT, 
				function() {
					self.show( cimd.global.connectionState.CONNECTED );
				}
			);
			cimd.controller.main.addListener( cimd.global.customEvent.connection.DISCONNECT,
				function(event) {
					var m,e= null;
					if( event.hasOwnProperty('message') ) {
						m = event.message;
					}
					if( event.hasOwnProperty('email') ) {
						e = event.email;
					}
					self.show( cimd.global.connectionState.DISCONNECTED, m, e );
				}
			);
			
		},
		
		show : function( state, message, email ) 
		{
			trace('userPanelController#show STATE=' + state +', message = '+message );
			var c = $( '#'+containerId ).empty();
		
			switch( state ) 
			{
				case cimd.global.connectionState.CONNECTED:
					// from var email
					c.append( $('<span>'+cimd.controller.main.connectedUser.linkedEmail+'&nbsp;</span>') );
					c.append( $('<a href="#">Se déconnecter</a>').click( 
						function() {
							cimd.controller.main.logout();
						} 
					));
					break;
				// OLD STUFF	
				case cimd.global.connectionState.CONNECTING:
					c.append( $('<span>patientez, connection en cours</span>') );
					break;
					
				case cimd.global.connectionState.DISCONNECTED:
				/*
					email = email || ''; // keep email on box
					var e = $('<input id="email" value="'+email+'" />');
					var p = $('<input id="password" type="password" />');
					var r = $('<input id="rememberMe" type="checkbox" />');
					c.append( e )
						.append( p )
						.append( r )
						.append( 
							$('<input type="button" value="Se connecter" />').click(
								function() {
									// LOGIN
									window.cimd.controller.main.login(
										e.val(), 
										p.val(),
										r.is(':checked')
									);	
								}
							)
						);
					if( message ) {
						c.append( $('<div>'+message+'</div>') );
					}
					// add onenterkeypress:
					
					$("#email, #password").keypress(function (e) 
					{
						if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
							c.find('input[type=button].default').click();
							return false;
						} else {
							return true;
						}
					});
				*/
					break;	
			}
		}
		//cm-userPanel
	};
	
})();
(function() {
	/*
	 * Defines the page count 
	 * and calls the libraryManager with the right parameters
	 * 
	 */
	
	var memento = {
		currentId : 0,
		storage : {}
	};	
	
	function LibraryController(pad, limit) 
	{
		Observer.call(this);
		
		this.pad = pad;
		
		this.limit = limit;
		this.currentOffset = this.pad;
		
		this.currentPage 	= 1;
		this.pageCount 		= 0;
		
		// Remember the initial position:
		memento.currentId = 0;
		memento.storage[ memento.currentId ] = {
			currentOffset 	: this.pad,
			currentPage 	: 1
		};
		
		var self=this;
		this.libraryManager = new cimd.service.LibraryManager(
			cimd.global.library.type.CENSORED
		);
		this.libraryManager.addListener(
			cimd.global.customEvent.common.COMPLETE, 
			function(event) 
			{
				// the first time
				if ( event.data.hasOwnProperty('local') ) {
					var c = event.data.local.cartoonsCount;
					self.pageCount = Math.ceil( c/limit );
				}
				event.data = jQuery.extend( 
					event.data,
					{
						'currentPage' : self.currentPage, 
						'pageCount' : self.pageCount
					} 
				);
				self.fire( event ); // bubble the event
			} 
		);
		
		this.libraryManager.addListener( 
			cimd.global.customEvent.common.ERROR_LOADING_DATA,
			function(event) {
				if( event.hasOwnProperty( 'data' ) ) {
					// Revert to old position:
					var d = memento.storage[event.data.ticket];
					if( d ) {
						self.currentOffset = d.currentOffset;
						self.pageCount = d.currentPage;
					}
	
					trace('LibraryController - Error ' + event.error );
					
				}
				self.fire( event ); // bubble the event
			} 
		);
	};
	Inheritance.extend( LibraryController, Observer );
	
	LibraryController.prototype.getCartoonsForRange = function( index, length ) {

	};

	LibraryController.prototype.getCartoons = function( init, user, backward ) 
	{
		var o, l = 0;
		if( init ) { // one time
		
			o = 0;
			l = this.limit + this.pad;
			
			this.libraryManager.init( 
				user, 
				{
					offset : o,
					limit : l
				}
			);
			this.currentPage = 1;
			
		} else {
			
			// Remember the last position:
			memento.storage[ ++memento.currentId ]={
				currentOffset : this.currentOffset,
				currentPage : this.currentPage
			};
			
			var currentPage = this.currentPage;
			///////////////////////////
			// Update the current page:
			if ( backward == false ) {
				this.currentOffset = this.currentOffset + this.limit; // check from total
				this.currentPage = Math.min( this.pageCount, this.currentPage+1 );
			} else {
				this.currentOffset = Math.max( this.pad, this.currentOffset - this.limit );
				this.currentPage = Math.max( 1, this.currentPage-1 );
			}

			// Do not call libraryManager if limit and offset does not change
			if( currentPage != this.currentPage ) 
			{
				o = this.currentOffset;
				l = this.limit;
				this.libraryManager.getAll( 
					user, 
					{
						offset : o,
						limit : l
					},
					{ 
						ticket : memento.currentId // give a ticket to know what action is request
					}
				);
			}
		}
	};
	
	window.cimd.view.controller.LibraryController = LibraryController;
	
})();
(function() {

	
	function FeedController( view, limit ) 
	{
		this.view = new cimd.view.Feeds('feeds');
		
		this.currenTimestamp = 0;
		this.limit = limit;
		this.jscr = null;
		this._firstLaunch = true;
		
		 	
		var s = this;
		s._updateData();
		/*
		
		-- TODO Manage update feeds every 8s
		
		setInterval( function() {
			s._updateData();
		}, 8000 );
		*/

	};
	
	FeedController.prototype._updateData = function() {
		this.req = cimd.global.CIMD_CONTROLLER
			+"?pattern=getnewfeeds&callback=c.feedUpdateCallback"
			+"&timestamp="+this.currenTimestamp
			+"&limit="+this.limit;
		//trace( this.req );
		// Create a new request object
		this.jscr = new JSONscriptRequest( this.req );
		this.jscr.buildScriptTag(); 
		this.jscr.addScriptTag();
	};
	
	FeedController.prototype.updateFeeds = function( data ) 
	{
		if( this._firstLaunch == true ) {
			this._firstLaunch = false;
			this._initFeeds( data );
		} else {
			this._updateFeeds( data );
		}
		this.jscr.removeScriptTag();
	};
	
	FeedController.prototype._updateFeeds = function( data ) 
	{
		if( data ) 
		{
			this.currenTimestamp = data.resultSet.timestamp;
			if( data.result ) {
				var f = null;
				var outData = new Array();
				for( var i=0,len=data.result.length;i<len;i++ ) 
				{
					f = data.result[i];
						
					var d = new Date();
					d.setTimestamp( f.date*1000, 's' );
					
					var thumbnail = cimd.service.media.getDataPathForId( f.dataid, 'public' );
					
					this.view.append({
						thumb : thumbnail,
						title : f.title,
						author : f.author,
						theme : f.theme,
						date : d.prettyDate()
					});
				}
			}
		}
		
	}; 
	
	FeedController.prototype._initFeeds = function( data ) 
	{
		if( data ) 
		{
			this.currenTimestamp = data.resultSet.timestamp;
			if( data.result ) {
				var f = null;
				var outData = new Array();
				for( var i=0,len=data.result.length;i<len;i++ ) {
					f = data.result[i];
					
					
					var d = new Date();
					d.setTimestamp( f.date*1000, 's' );
					
					var thumbnail = cimd.service.media.getDataPathForId( f.dataid, 'public' );
					
					outData.push({
						thumb : thumbnail,
						title : f.title,
						author : f.author,
						theme : f.theme,
						date : d.prettyDate()
					});
				}
				this.view.appendAll( outData.reverse() );
			}
		}
	};
	
	
	window.cimd.controller.FeedController = FeedController;
	
})();
(function() {
	var events = cimd.global.customEvent;
	var StripController = function() {
		this.current = 0;
		
		Observer.call(this);
	};
	Inheritance.extend( StripController, Observer );
	
	StripController.prototype.reset = function() {
		this.current = -1;
	};
	
	
	StripController.prototype.goTo = function( itemNum, libraryData, length ) {
		var e = {};
		var newPosition = Math.floor( itemNum / cimd.global.STRIP_ITEM_COUNT ) * cimd.global.STRIP_ITEM_COUNT;
		if( this.current != newPosition ) 
		{
			var oldPosition = libraryData.it;
			//this.current = 0;
			trace( libraryData);
			if( libraryData.goTo(itemNum) ) {
				e.type = events.actions.NEXT_STRIP_REQUESTED
				if( itemNum < this.current ) {
					e.type = events.actions.PREVIOUS_STRIP_REQUESTED
				}
				e.data = {
					cartoons : libraryData.current()
				};
				this.fire( e );
				this.current = newPosition;
				
				trace( e.type,newPosition, this.current );
			} else {
				trace( 'ERROR',itemNum );
			}
		}

	};
	
	StripController.prototype.next = function( libraryData, length ) 
	{
		var e = {};
		if(  !libraryData.next() ) {
			// request a next library load
			e.type = events.actions.LIBRARY_LOAD_REQUESTED,
			e.data = {
				direction:'next'
			};			
		} else {
			e.type = events.actions.NEXT_STRIP_REQUESTED
			e.data = {
				cartoons : libraryData.current()
			}
			this.current = Math.floor( libraryData.it / cimd.global.STRIP_ITEM_COUNT ) * cimd.global.STRIP_ITEM_COUNT;
		}
		this.fire( e );
	};	
		
	
	StripController.prototype.previous = function( libraryData, length ) 
	{
		var e = {};
		if( !libraryData.previous() ) {
			// request a next library load
			e.type = events.actions.LIBRARY_LOAD_REQUESTED,
			e.data = {
				direction:'previous'
			};
		} else {
			trace( libraryData.current() );
			e.type = events.actions.PREVIOUS_STRIP_REQUESTED
			e.data = {
				cartoons : libraryData.current()
			}
			this.current = Math.floor( libraryData.it / cimd.global.STRIP_ITEM_COUNT ) * cimd.global.STRIP_ITEM_COUNT;
		}

		this.fire( e );
	};

	window.cimd.view.controller.StripController = StripController;
	
})();
(function() {

	var hSlView = null;

	var StripView = function() {
		this.pane = 0;
		this.container = null;
		this.init();
		Observer.call(this);
	};	
	Inheritance.extend( StripView, Observer );		
		
	StripView.prototype.init = function( containerEl ) {
		this.container = $('#stripCartoons');
		hSlView = new HorizontalSlideView( $('#content-big-cartoons'), 2 );
	};
	
	StripView.prototype.slideAndDisplayPrevious = function( data ) 
	{
		var s = this;
		var cartoons = data.cartoons;
		
		var displayList = new Array(), c = null;
		for( var i=0,len=cartoons.length;i<len;i++ ) 
		{
			c = cartoons[i];
			trace( c );
			if( c ) {
				// TODO use a factory
				dc = new window.cimd.view.DisplayableCartoon(
						c, window.cimd.view.DisplayableCartoonSize.LARGE
					);
				displayList.push( dc );
			}
		}
		
		if( this.pane > 0 ) {
		
			hSlView.appendBeforeAndSlide( displayList, function() {
				var count = 0;
				s.pane++;
				// load each image before display it:
				for( var i=0,len=displayList.length;i<len;i++ ) {
					displayList[i].load( function() {
						// this is <img/>
						$(this).fadeIn("slow");
						if( ++count == len ) {
							s.fire(cimd.global.customEvent.views.REQUESTED_STRIP_COMPLETED);
						}
					});
				}
			});

		} else {

			hSlView.append( displayList, function() {
				var count = 0;
				s.pane++;
				// load each image before display it:
				for( var i=0,len=displayList.length;i<len;i++ ) {
					displayList[i].load( function() {
						// this is <img/>
						$(this).fadeIn("slow");
						if( ++count == len ) {
							s.fire(cimd.global.customEvent.views.REQUESTED_STRIP_COMPLETED);
						}
					});
				}
			});
		}

	};
	
	
	StripView.prototype.slideAndDisplayNext = function( data ) 
	{			
		var s = this;
		var cartoons = data.cartoons;
		
		var displayList = new Array(), c = null;
		for( var i=0,len=cartoons.length;i<len;i++ ) 
		{
			c = cartoons[i];
			trace( c );
			if( c ) {
				dc = new window.cimd.view.DisplayableCartoon(
						c, window.cimd.view.DisplayableCartoonSize.LARGE
					);
				
				displayList.push( dc );
			}
		}
		
		trace( displayList.length );
		
		if( this.pane > 0 ) {
		
			hSlView.appendAfterAndSlide( displayList, function() {
				var count = 0;
				s.pane++;
				// load each image before display it:
				for( var i=0,len=displayList.length;i<len;i++ ) {
					displayList[i].load( function() {
						// this is <img/>
						$(this).fadeIn("slow");
						if( ++count == len ) {
							s.fire(cimd.global.customEvent.views.REQUESTED_STRIP_COMPLETED);
						}
					});
				}
			});

		} else {

			hSlView.append( displayList, function() {
				var count = 0;
				s.pane++;
				// load each image before display it:
				for( var i=0,len=displayList.length;i<len;i++ ) {
					displayList[i].load( function() {
						// this is <img/>
						$(this).fadeIn("slow");
						if( ++count == len ) {
							s.fire(cimd.global.customEvent.views.REQUESTED_STRIP_COMPLETED);
						}
					});
				}
			});
		}
	};
	
	cimd.view.StripView = StripView;
})();
(function() {

	var SimpleStore = function() 
	{
		this.STORE_CONTAINER_ID = 'cm-content-store';	
		this.AVAILABLE_SUBSCRIPTIONS = 'subscriptions-available';
		this.AVAILABLE_SUBSCRIPTIONS_PERSONNEL = 'subscriptions-available-personnel';
		
		this.currency = window.common.currency.EUR;
			
		this.pages = {
			'loading'		: 'store-loading',
			'plan' 			: 'store-plan',
			'explanation'	: 'store-message',
			'preapproval' 	: 'store-preapproval-workflow',
			'waiting' 		: 'store-waiting'
		};
		
		var s = this;
		this._preapprovalWorkFlow = new cimd.view.PreapprovalWorkFlow();
		this._preapprovalWorkFlow.addListener( 'requestNextStep', function() {
			s._preapprovalWorkFlow.goNextStep();
			s.display( 'preapproval' );
			
			
		});
		this._preapprovalWorkFlow.addListener( 'requestPreviousStep', function() {
			s._preapprovalWorkFlow.goPreviousStep();
			s.display( 'preapproval' );
			
		});
		this._preapprovalWorkFlow.addListener( cimd.global.customEvent.store.REQUEST_PREAPPROVED_PLAN, function(event) {
			s.display( 'waiting' );
			s.fire( event ); // event bubbling
		});
		Observer.call(this);
	};
	Inheritance.extend( SimpleStore, Observer );
	
	SimpleStore.prototype.setCurrency = function( currency ) {
		if( window.common.currency.test( currency ) ) {
			this.currency = currency;
			// TODO reload store ?
		}
	};
	
	SimpleStore.prototype.load = function( mainContent, oncomplete ) {
		var s = this;
		$('#preapprovalRequest').click(function() {
			s.display('preapproval');
		});
		$('input[name=availablePlanRequest]').click(function() {
			s.display('plan');
		});	
		
		if( oncomplete )
			oncomplete();
	};
		
	SimpleStore.prototype.show = function( subscriptions ) {			
		$('#'+this.STORE_CONTAINER_ID).animate({
			opacity: 1,
			height: 'toggle'
			}, 1000, function() {
				// Animation complete.
			}
		);
	};
		
	SimpleStore.prototype.hide = function() {
		
		$('#'+this.STORE_CONTAINER_ID).animate({
			opacity: 0,
			height: 'toggle'
			}, 1000, function() {
				// Animation complete.
			}
		);
	};
		
	SimpleStore.prototype.display = function( page, key ) 
	{
		var s = this;
		if( this.pages.hasOwnProperty( page ) ) 
		{
			var id = this.pages[ page ];
			
			if( page == "preapproval" ) {
				id = this._preapprovalWorkFlow.getCurrentStep();
				
			}
			
			if( page == 'explanation' ) {
			//	trace("show",id,"show",key );
				$( "#"+id+' .content' ).css('display','none');
				$( "#"+key ).css('display','block'); // display the right error code
			}
			if( page == 'loading' ) {
				$( "#"+id+' .content' ).css('display','block');
			}
			
			var p = $( "#"+id ).position();
			trace( p );
			if( p ) {
				$('#store-view-container').animate(
					{ 'left': -p.left},
					440);
			}
		}
	};

	SimpleStore.prototype.getPreapprovalRequestPanel = function() 
	{
		var s = this;
		// construct the currency selector:
		var currencySelector = $('<select id="currencySelector" name="currency"></select')
			.change(function() {
				// update
				var v = common.currency.formatValueForCurrency( 
					$('#sliderAmount').slider( "option", "value" ),
					$(this).val() 
				);
				$("#amount").html( v );
			});
			
		var c = window.common.currency.getCurrencies();
		var i = c.length, o = null;
		while( i-- ) {
			var cur = c[i];
			if (cur != common.currency.points) 
			{
				o = $('<option value="' + cur + '">' + common.currency.translated[cur] + '</option>');
				trace( cur, this.currency );
				if( cur == this.currency ) {
					o.attr('selected', true );
				}
				currencySelector.append( o );
			}
		}

		var m = $('<table class="content" style="margin-left:90px"></table>');
		
		var tr1 = $( '<tr></tr>' );
		var td1 = $( '<td><h4>Sélection de la devise :</h4></td>' );
		var td2 = $( '<td></td>' );
		td2.append( currencySelector );
		tr1.append( td1 )
		   .append( td2 );
		   
		var tr2 = $( '<tr></tr>' );
		var td3 = $( '<td colspan="2"></td>' );
		td3.append( $('<h4 style="float:left">Montant maximum autorisé : </h4>' ) )
		   .append( $('<div id="amount" style="color:white;font-size:16px;margin:5px 0;float:left"></div>').html( cimd.global.store.preapproval.MIN_AMOUNT ) )
		   .append( $('<div id="sliderAmount"></div>').slider({
			range: "min",
			step: 1,
			min: cimd.global.store.preapproval.MIN_AMOUNT,
			max: cimd.global.store.preapproval.MAX_AMOUNT,
			slide: function(event, ui) {
				var v = common.currency.formatValueForCurrency( 
					ui.value ,
					$('#currencySelector').val() 
				);
				$("#amount").html( v );
			}
		}))
		tr2.append( td3 );
		   
		var tr3 = $( '<tr></tr>' );
		var td5 = $( '<td colspan="2"><h4>Date limite de validité du plan Paypal:</h4></td>' );
		tr3.append( td5 );
		   
		var tr4 = $( '<tr></tr>' );
		var td6 = $( '<td colspan="2"></td>' );
		td6.append( $('<div id="datePicker"></div>').datepicker(
			{ minDate: +1, maxDate: '+1Y',showAnim:false}
		) )
		tr4.append( td6 );
		   
		var tr5 = $( '<tr height="30"></tr>' );
		var td7 = $( '<td colspan="2"></td>' );
		td7.append( $('<div><input type="button" value="Valider" ></input></div>').click(
			function() {
				var amount = $('#sliderAmount').slider( "option", "value" );
				if( amount == 0 ) {
					amount = 1;
				}
				s.display('waiting');
				var e = {
					type : cimd.global.customEvent.store.REQUEST_PREAPPROVED_PLAN,
					data : {
						currency : $("#currencySelector option:selected").val(),
						endingdate : $('#datePicker').val(),
						maxtotalamountofallpayments : amount
					}
				}
				s.fire(e);
			})
		);
		tr5.append( td7 )
		   
		m.append( tr1 )
		 .append( tr2 )
		 .append( tr3 )
		 .append( tr4 )
		 .append( tr5 );
		return m;	
	};
	
	SimpleStore.prototype.setWaiting = function( flag ) {	
		if ( flag == true ) {
			this.display('loading');
		}
	};
	
	SimpleStore.prototype.addAvailableSubscription = function( subscription ) 
	{
		// NEED a flag
		trace('addAvailableSubscription',subscription);
		var s = this;
		var p = subscription.prices[this.currency];
		var thumb = '../images/transparent.png';
		var authorName = '&nbsp;';
		
		
		if( subscription.id == cimd.global.subscription.AUTHOR ) {
			authorName = subscription.author.name;
			thumb =  cimd.service.media.getDataPathForId( subscription.author.thumb );
			
			var sub = $('<li class="subscription" style="float:left;margin:0 32px"></li>')
			
			var matable = $('<table width="410"></table>');
			sub.append( matable );
			
			var montr = $('<tr></tr>');
			matable.append( montr );
			
				montr.append( '<td class="thumb" width="70"><img width="40" src="'+thumb+'" /></td>' )
			//	.append( '<td class="type">'+subscription.type+'</td>' )
				.append( '<td class="type" width="140">'+ authorName + '</td>')
				.append( '<td class="prix" width="114">'+p+'</td>' );
				
			montr.append( $('<td width="86"><div class="btn-souscrire"></div></td>' ).click(
				function() {
					s.fire({
						type:cimd.global.customEvent.store.ADD_SUBSCRIPTION_REQUEST,
						data : subscription
					});
				}
			));
			$('#'+this.AVAILABLE_SUBSCRIPTIONS_PERSONNEL).append( sub );
		
					
		} else{
			// subscription line:
			var sub = $('<tr class="subscription" height="40"></tr>')
				.append( '<td class="type" width="210"><div class="titleFormule">'+subscription.type+'</div></td>' )
			//	.append( '<td class="author">'+ authorName + '</td>')
				.append( '<td class="prix" width="114">'+p+'</td>' );
				
			sub.append( $('<td width="86"><div class="btn-souscrire"></div></td>' ).click(
				function() {
					s.fire({
						type:cimd.global.customEvent.store.ADD_SUBSCRIPTION_REQUEST,
						data : subscription
					});
				}
			));
			
			
			
			$('#'+this.AVAILABLE_SUBSCRIPTIONS).append( sub );
			
		}
		
		
		if( subscription.id == 3 ) {
			//subscription.extra
		}	
			
		
		
	};
	
	window.cimd.view.store.SimpleStore = SimpleStore;
	
})();
(function() {
	var PreapprovalWorkFlow = function() {
		this._current = 0;
		this.steps=[
		  'currency-chooser',
		  'duration-chooser',
		  'amount-chooser'	           
		];
		this._minIndex = 0;
		this._maxIndex = (this.steps.length-1);
		
		// default data:
		this.collectedData = {
			currency : window.common.currency.EUR,
			duration : cimd.global.store.preapproval.duration.ONE_WEEK,
			amout : cimd.global.store.preapproval.MIN_AMOUNT
		};
		
		this._initView();
		Observer.call(this);
	};
	Inheritance.extend( PreapprovalWorkFlow, Observer );
	
	PreapprovalWorkFlow.prototype._initView = function() {
		var s = this;
		
		$('#currencySelector').find('span').click(function() {
			var $this = $(this);
			var id = $this.attr('id');
			var c = window.common.currency.EUR;
			switch( id ) {
				case 'euro':
					c = window.common.currency.EUR;
					break;
				case 'dollar':
					c = window.common.currency.USD;		
					break;	
				case 'pound':
					c = window.common.currency.GBP;
					break;
			}
			s.collectedData.currency = c;
			$('#currencySelector .selected').removeClass('selected');
			$this.addClass( 'selected' );
			
			// bind
			var v = common.currency.formatValueForCurrency( 
				cimd.global.store.preapproval.MIN_AMOUNT ,
				s.collectedData.currency
			);
			$("#amountNumber").html( v );
			
			s.fire( 'requestNextStep' );
		});
		
		$('#durationSelector').find('.duration').click(function() {
			var $this = $(this);
			var id = $this.attr('id');
			var c = cimd.global.store.preapproval.ONE_MONTH;
			switch( id ) {
				case 'oneWeek':
					c = cimd.global.store.preapproval.duration.ONE_WEEK;
					break;
				case 'oneMonth':
					c =  cimd.global.store.preapproval.duration.ONE_MONTH;		
					break;	
				case 'threeMonthes':
					c =  cimd.global.store.preapproval.duration.THREE_MONTHES;
					break;
				case 'sixMonthes':
					c =  cimd.global.store.preapproval.duration.SIX_MONTHES;
					break;
			}
			s.collectedData.duration = c;
			$('#durationSelector .selected').removeClass('selected');
			$this.addClass( 'selected' );
			s.fire( 'requestNextStep' );
		});
		
		$('#amountSlider').slider({
			range: "min",
			min: cimd.global.store.preapproval.MIN_AMOUNT,
			max: cimd.global.store.preapproval.MAX_AMOUNT,
			slide: function(event, ui) {
				var v = common.currency.formatValueForCurrency( 
					ui.value ,
					s.collectedData.currency
				);
				$("#amountNumber").html( v );
				s.collectedData.amount = ui.value
			}
		});
		
		$('#validatePreapprovalPlanButton').click(function() {
			var e = {
				type : cimd.global.customEvent.store.REQUEST_PREAPPROVED_PLAN,
				data : {
					currency : s.collectedData.currency,
					duration : s.collectedData.duration,
					maxtotalamountofallpayments : s.collectedData.amount||1
				}
			}
			s.fire(e);
		});
		
		$('.boBackStep').click(function(){
			s.fire( 'requestPreviousStep' );
		});
	};
	
	
	PreapprovalWorkFlow.prototype.goNextStep = function() {
		this._current = Math.min( this._maxIndex, this._current+1 );
		//this.goCurrentStep();
	};
	PreapprovalWorkFlow.prototype.goPreviousStep = function() {
		this._current = Math.max( this._minIndex, this._current-1 );
		//this.goCurrentStep();
	};
	PreapprovalWorkFlow.prototype.getCurrentStep = function() {
		trace( 'PreapprovalWorkFlow.prototype.goCurrentStep : ' + this.steps[ this._current ] );
		return this.steps[ this._current ];
	};
	
	window.cimd.view.PreapprovalWorkFlow = PreapprovalWorkFlow;
})();
(function() {

	var ComplexStore = function( currency ) 
	{
		this.visible = false;
		this.currency = currency||window.common.currency.EUR;
		this.pages = {
			'loading'		: 'store-loading',
			'plan' 			: 'store-plan',
			'explanation'	: 'store-message',
			'preapproval' 	: 'store-preapproval',
			'waiting' 		: 'store-waiting'
		};
		
		this.STORE_CONTAINER_ID = 'cm-store';	
		this.PERSONAL_SUBSCRIPTIONS = 'subscriptions-personal';
		this.AVAILABLE_SUBSCRIPTIONS = 'subscriptions-available';
		
		this._ownWasEmpty = true;
		this._avaWasEmpty = true;
		
		Observer.call(this);
	};
	Inheritance.extend( ComplexStore, Observer );
	
	ComplexStore.prototype.load = function( container, oncomplete ) 
	{
		var c = $('#'+this.STORE_CONTAINER_ID);
		if ( c.length == 0 ) 
		{				
			c = $('<div></div>').attr('id', this.STORE_CONTAINER_ID);
			$( "#"+container ).append( c );
		}
		var s = this;
		c.empty().load(
			'/resources/store.html',
			function() 
			{	
				var preapprovalPanel = s.getPreapprovalRequestPanel();
				$('#store-preapproval').append( preapprovalPanel );
				
				$('#'+s.STORE_CONTAINER_ID+' input[name=preapprovalRequest]').click(function() {
					s.display('preapproval');
				});
					
				$('#'+s.STORE_CONTAINER_ID+' input[name=availablePlanRequest]').click(function() {
					s.display('plan');
				});	
				
				if( oncomplete ) 
					oncomplete.call();
			}
		);
	};
	
	ComplexStore.prototype.setCurrency = function( currency ) {
		if( window.common.currency.test( currency ) ) {
			this.currency = currency;
			// TODO reload store ?
		}
	};
	
	ComplexStore.prototype.setWaiting = function( flag ) {	
		if ( flag == true ) {
			this.display('loading');
		}
	};
	
	ComplexStore.prototype.addOwnSubscription = function ( subscription ) 
	{
		// NEED a flag
		var p = subscription.prices[this.currency];
		
		if( this._ownWasEmpty == true ) {
			this._ownWasEmpty = false;
			$('#'+this.PERSONAL_SUBSCRIPTIONS).append(
				$('<tr class="subscription title main">'
					+'<td colspan="5">Abonnements en cours</td>'
				+'</tr>')
			);
			$('#'+this.PERSONAL_SUBSCRIPTIONS).append(
				$('<tr class="subscription title">'
					+'<td class="thumb"></td>'
					+'<td class="type"></td>'
					+'<td class="prix">Pour 30 jours</td>'
					+'<td class="prix">Expiration</td>'
					+'<td></td>'
				+'</tr>')
			);
			$('#'+this.PERSONAL_SUBSCRIPTIONS).append(
				$('<tr class="subscription title">'
					+'<td colspan="5"></td>'
				+'</tr>')
			);
		}

		var settings = $('<td class="settings">[settings]</td>').click(
			function(){
				// TODO settings here 
				// filter
			}
		);
		var thumb = 'images/transparent.png';
		var authorName = '&nbsp;';
		if( subscription.id == cimd.global.subscription.AUTHOR ) 
		{
			authorName = subscription.author.name;
			
			var authors = cimd.controller.main.data().authors;
			var author = authors[ subscription.author.id ];
			if( author )
				thumb =  cimd.service.media.getDataPathForId( author.thumb );
				
			// subscription line:
			var sub = $('<tr class="subscription"></tr>')
				.append( '<td class="thumb"><img width="40" src="'+thumb+'" /></td>' )
				//.append( '<td class="type">'+subscription.type+'</td>' )
				.append( '<td class="type">'+ authorName + '</td>')
				.append( '<td class="prix">'+p+'</td>' )
				/*.append( settings )*/
				.append( '<td class="date">'+subscription.endDate+'</td>' )
				.append( $('<td><div class="btn-renouvelle"></div></td>' ).click(
					function() {
						// RENEW SUBSCRIPTION
						// TODO fire an event
						window.cimd.controller.main.renewSubscription( subscription );
					}
				));			
		} else {
		
			// subscription line:
			var sub = $('<tr class="subscription"></tr>')
				.append( '<td class="thumb"><img width="40" src="'+thumb+'" /></td>' )
				.append( '<td class="type">'+subscription.type+'</td>' )
				//.append( '<td class="author">'+ authorName + '</td>')
				.append( '<td class="prix">'+p+'</td>' )
				/*.append( settings )*/
				.append( '<td class="date">'+subscription.endDate+'</td>' )
				.append( $('<td><div class="btn-renouvelle"></div></td>' ).click(
					function() {
						// RENEW SUBSCRIPTION
						window.cimd.controller.main.renewSubscription( subscription );
					}
				));
		}	
		$('#'+this.PERSONAL_SUBSCRIPTIONS).append( sub );
	};
		
	ComplexStore.prototype.addAvailableSubscription = function( subscription ) 
	{
		
		if( this._avaWasEmpty == true ) {
			this._avaWasEmpty = false;
			$('#'+this.AVAILABLE_SUBSCRIPTIONS).append(
				$('<tr class="subscription title main">'
					+'<td colspan="5">Abonnements disponibles</td>'
				+'</tr>')
			);
			
			$('#'+this.AVAILABLE_SUBSCRIPTIONS).append(
				$('<tr class="subscription title">'
					+'<td class="thumb"></td>'
					+'<td class="type"></td>'
					+'<td class="prix">Pour 30 jours</td>'
					+'<td class="prix"></td>'
					+'<td></td>'
				+'</tr>')
			);
			$('#'+this.AVAILABLE_SUBSCRIPTIONS).append(
				$('<tr class="subscription title">'
					+'<td colspan="5"></td>'
				+'</tr>')
			);
		}
		
		// NEED a flag
		var p = subscription.prices[ this.currency ];
		var thumb = 'images/transparent.png';
		var authorName = '&nbsp;';
		if( subscription.id == cimd.global.subscription.AUTHOR ) {
			authorName = subscription.author.name;
			thumb =  cimd.service.media.getDataPathForId( subscription.author.thumb );	
			var sub = $('<tr class="subscription"></tr>')
				.append( '<td class="thumb"><img width="40" src="'+thumb+'" /></td>' )
			//	.append( '<td class="type">'+subscription.type+'</td>' )
				.append( '<td class="type">'+ authorName + '</td>')
				.append( '<td class="prix">'+p+'</td>' );
					
		} else {
			// subscription line:
			var sub = $('<tr class="subscription"></tr>')
				.append( '<td class="thumb"><img width="40" src="'+thumb+'" /></td>' )
				.append( '<td class="type">'+subscription.type+'</td>' )
			//	.append( '<td class="author">'+ authorName + '</td>')
				.append( '<td class="prix">'+p+'</td>' );

		}
		
		if( subscription.id == 3 ) {
			//subscription.extra
		}	
			
		sub.append( $('<td><div class="btn-souscrire"></div></td>' ).click(
			function() {

				// RENEW SUBSCRIPTION
				window.cimd.controller.main.addSubscription( subscription );
			}
		));
			
		$('#'+this.AVAILABLE_SUBSCRIPTIONS).append( sub );
	};
		
	ComplexStore.prototype.show = function( subscriptions ) 
	{
		
		if ($('#' + this.PERSONAL_SUBSCRIPTIONS).is(":empty")) {
			$('#' + this.PERSONAL_SUBSCRIPTIONS).empty().append('<tr><td>Pas de plan disponible</td></tr>');
		}
		if ($('#' + this.AVAILABLE_SUBSCRIPTIONS).is(":empty")) {
			$('#' + this.AVAILABLE_SUBSCRIPTIONS).empty().append('<tr><td>Pas de plan disponible</td></tr>');
			$('#store-view-container').css('height','123px');
		}
		if( this.visible == false ) 
		{
			var s = this;
			$('#'+this.STORE_CONTAINER_ID).animate({
				opacity: 1,
				height: 'toggle'
				}, 1000, function() {
					s.visible = true;
				});
		}
	};
		
	ComplexStore.prototype.hide = function() {
		var s = this;
		$('#'+this.STORE_CONTAINER_ID).animate({
			opacity: 0,
			height: 'toggle'
			}, 1000, function() {
				s.visible = false; 
			});
	};
		
	ComplexStore.prototype.display = function( page,key ) 
	{
		trace( 'ComplexStore#display' , page, key || '' );
		if( this.pages.hasOwnProperty( page ) ) {
			$( '#store-loading .content' ).css('display','none');
			
			var id = this.pages[ page ];
			if( page == 'explanation' ) {
				$( "#"+id+' .content' ).css('display','none');
				$( "#"+key ).css('display','block'); // display the right error code
			} else
			if( page == 'loading' ) {
				$( "#"+id+' .content' ).css('display','block');
			}
			
			var p = $( "#"+id ).position();
			if( p ) {
				$('#store-view-container').animate(
					{ 'left': -p.left},
					440);
			}
		}		
	};
	
	ComplexStore.prototype.getPreapprovalRequestPanel = function() 
	{
		var s = this;
		// construct the currency selector:
		var currencySelector = $('<select id="currencySelector" name="currency"></select')
			.change(function() {
				// update
				var v = common.currency.formatValueForCurrency( 
					$('#sliderAmount').slider( "option", "value" ),
					$(this).val() 
				);
				$("#amount").html( v );
			});
			
		var c = window.common.currency.getCurrencies();
		var i = c.length, o = null;
		while( i-- ) {
			var cur = c[i];
			if (cur != common.currency.points) 
			{
				o = $('<option value="' + cur + '">' + common.currency.translated[cur] + '</option>');
				if( cur == this.currency ) {
					o.attr('selected', true );
				}
				currencySelector.append( o );
			}
		}

		var m = $('<table class="content" style="margin-left:90px"></table>');
		
		var tr1 = $( '<tr></tr>' );
		var td1 = $( '<td><h4>Sélection de la devise :</h4></td>' );
		var td2 = $( '<td></td>' );
		td2.append( currencySelector );
		tr1.append( td1 )
		   .append( td2 );
		   
		var tr2 = $( '<tr></tr>' );
		var td3 = $( '<td colspan="2"></td>' );
		td3.append( $('<h4 style="float:left">Montant maximum autorisé : </h4>' ) )
		   .append( $('<div id="amount" style="color:white;font-size:16px;margin:5px 0;float:left"></div>').html( cimd.global.store.preapproval.MIN_AMOUNT ) )
		   .append( $('<div id="sliderAmount"></div>').slider({
				range: "min",
				min: cimd.global.store.preapproval.MIN_AMOUNT,
				max: cimd.global.store.preapproval.MAX_AMOUNT,
				slide: function(event, ui) {
					var v = common.currency.formatValueForCurrency( 
						ui.value ,
						$('#currencySelector').val() 
					);
					$("#amount").html( v );
				}
			}));
		tr2.append( td3 );
		   
		var tr3 = $( '<tr></tr>' );
		var td5 = $( '<td colspan="2"><h4>Date limite de validité du plan Paypal:</h4></td>' );
		tr3.append( td5 );
		   
		var tr4 = $( '<tr></tr>' );
		var td6 = $( '<td colspan="2"></td>' );
		td6.append( $('<div id="datePicker"></div>').datepicker(
			{ minDate: +1, maxDate: '+1Y',showAnim:false}
		) )
		tr4.append( td6 );
		   
		var tr5 = $( '<tr height="30"></tr>' );
		var td7 = $( '<td colspan="2"></td>' );
		td7.append( $('<div><input type="button" value="" id="btnValider" ></input></div>').click(
			function() {
				var amount = $('#sliderAmount').slider( "option", "value" );
				if( amount == 0 ) {
					amount = 1;
				}
				s.display('waiting');
				var e = {
					type : cimd.global.customEvent.store.REQUEST_PREAPPROVED_PLAN,
					data : {
						currency : $("#currencySelector option:selected").val(),
						endingdate : $('#datePicker').val(),
						maxtotalamountofallpayments : amount
					}
				}
				s.fire(e);
			})
		)
		   .append('<input name="availablePlanRequest" type="button" value="" class="btnAnnuler" />');
		tr5.append( td7 )
		   
		m.append( tr1 )
		 .append( tr2 )
		 .append( tr3 )
		 .append( tr4 )
		 .append( tr5 );
		return m;	
	};
	
	window.cimd.view.store.ComplexStore = ComplexStore;
	
})();
(function() {

	var MAIN_CONTAINER_ID = 'mainContent';
	
	var Library = function() {
		this.container = 'cm-library';
		this.isInit = false;
		Observer.call( this );
	};
	Inheritance.extend( Library, Observer );
	
	
	Library.prototype.destroy = function() {
		// TODO: fade out then remove all
		$("div#mainContent").empty();
	};
	
	Library.prototype.display = function( libraryModel ) 
	{
		var lv = $("div#mainContent");
		if (libraryModel.cartoons && libraryModel.cartoons.length > 0) 
		{
			var c = li = null;						
			var mediumView = $('<ul id="mainLibrary"></ul>')
				.addClass("cartoons medium")
				.addClass("loading");
			
			this.displaySmallImages(
				mediumView,
				libraryModel.cartoons, 
				0 //	cimd.global.STRIP_ITEM_COUNT
			);
			
			lv.append( mediumView );
		}
	};
		
	Library.prototype.update = function( libraryModel ) 
	{			
		if (libraryModel.cartoons && libraryModel.cartoons.length > 0) 
		{
			var mediumView = $("ul#mainLibrary").empty();
			this.displaySmallImages( mediumView, libraryModel.cartoons, 0 ); //cimd.global.STRIP_ITEM_COUNT );
		}
	};
	
	

	Library.prototype.initControllerView = function(currentPage, totalPage) 
	{
		
		var buttonBar = $('#cm-libraryButtonBar');
		if( buttonBar.length != 0 ) {
			buttonBar.empty();
		} else {
			buttonBar = $('<div id="cm-libraryButtonBar"></div>');
			$("div#"+cimd.view.library.container).append( buttonBar );
		}

		var previous = $('<span />').attr('id','arrow-leftButtonBar');
		var next = $('<span />').attr('id','arrow-rightButtonBar');
		
		next.click(function() {
			trace( this );
			// showNext panel of cartoons
			window.cimd.controller.main.displayLibrary(false);
		});
		previous.click(function() {
			// showNext panel of cartoons
			trace( this );
			window.cimd.controller.main.displayLibrary(true);
		});
		
		var pageInfo = $('<div id="middleButtonBar">'+currentPage+'/'+totalPage+'</div>');
		
		
		buttonBar.append( previous )
				.append(pageInfo)
				.append( next );
	};

	// SMALL IMAGES
	Library.prototype.displaySmallImages = function( view, cartoons, offset ) 
	{
		var dc, li, c = null;
		var s = this;
		
		view.empty().removeClass('loading');
		
		var len = cartoons.length;
		for (var i = offset; i < len; i++) {
			c = cartoons[i];
			if (c) 
			{
				li = $("<li></li>");
				if( c.censored == true ) {
					li.addClass( 'censored' );
				}
				
				li.bind( 'click' , function(num) {
					return function() {
						s.fire({
							type : cimd.global.customEvent.views.LIST_ITEM_CLICK,
							itemindex : num 
						});
					}
				}(i));
				
				/*
				li.bind('click', function(mediaPath,title) {
					return function(){
						$.fancybox({
							'orig'	: $(this),
							'padding' : 0,
							'href' : mediaPath,
							'title':title,
							
							'speedIn' : 500,
							'speedOut' : 300,
							'transitionIn'	: 'elastic',
							'transitionOut'	: 'elastic',
							'easingIn'      : 'easeOutBack',
							'easingOut'     : 'easeInBack'
						});
						//window.cimd.view.mediaViewer.show(mediaPath);
					};
				}(c.media, c.title));
				*/
				
				dc = new window.cimd.view.DisplayableCartoon(
						c, window.cimd.view.DisplayableCartoonSize.MEDIUM
					);
				
				dc.appendTo( li );
				
				dc.load( function() {
					// this is <img/>
					//$(this).css('display','block');
					$(this).fadeIn("fast");
				});
				view.append( li );
			}
		}
	};
	window.cimd.view.library = new Library();
})();
(function() {
	var SHADOW_BOX = "cimdWiewerContainer";
	var VIEWER = "cimdMediaViewer";
	
	window.cimd.view.mediaViewer = {
		show : function( path ) {
			var mv = getMediaViewer().css('display', 'none');
			getShadowBox()
				.empty().fadeIn( 600, 
					function() {
						var img = new Image();
						$(img).load(function () 
						{
							mv.empty()
								.append( $(this) )
								.css('display', 'block');
						})
						.error(function () {
							// Error
						}).attr( 'src', path );
					}
				);
		}
	};
	
	function getMediaViewer() {
		var mv = $("#" + VIEWER);
		if (!mv.length) {
			mv = $("<div></div>")
				.attr("id", VIEWER)
				.click( function() {
					$("#" + SHADOW_BOX).fadeOut( 200 , function() {
						mv.css('display', 'none');
					});
				});
			$(document.body).append( mv );			
		}
		return mv.css('display', 'none');
	}
	
	function getShadowBox() 
	{
		var sb = $("#" + SHADOW_BOX);
		if ( !sb.length ) 
		{
			sb = $("<div></div>").attr("id", SHADOW_BOX)
					.css('opacity',0.6)
					.click( function() {
						$(this).fadeOut( 200 , function() {
							//css('display', 'none');
						});
					});
			$(document.body).append( sb );
		}
		return sb.css('display', 'none');
	};
})();

(function() {
	
	var HORIZONTAL_LARGE_WIDTH	= 477;
	var VERTICAL_LARGE_WIDTH	= 315;
	
	var MEDIUM_WIDTH = 70;//140;
	var SMALL_WIDTH	= 30;
	
	function DisplayableCartoon( cartoon, size ) 
	{
		
		this.id = null;
		this.image = null;
		this.$element = null;

		///////////
		// COMMMON
		this.id =  cartoon.id;// store the cartoon id
				
		this.$element = $("<div></div>").addClass('cartoon');
		this.$element.attr("id", "ct-" + cartoon.id);
		this.source = null;
		// Visual media
		this.image = new Image();
		$(this.image).hide();
		
		switch( size ) 
		{
			case cimd.view.DisplayableCartoonSize.LARGE:
			
				this.source = cartoon.media;
				// Textual information
				var information = $('<div class="information"></div>' );
				information.append( $('<div class="title">'+cartoon.title+'</div>') )
					.append( $('<div class="author">'+cartoon.author+'</div>') )
					.append( $('<div class="date">'+cartoon.publicationDate+'</div>') );
				
				// position exception
				if( cartoon.position == 'h' ) {
					this.$element.addClass( 'horizontal' ); 
					this.image.width = HORIZONTAL_LARGE_WIDTH;			
				} else {
					this.$element.addClass( 'vertical' );
					this.image.width = VERTICAL_LARGE_WIDTH;	
				}

				// append all				
				this.$element
					.append( '<div class="cartoonMark"></div>' )
					.append( this.image )
					.append( information );	
				
				break;
				
			
			case cimd.view.DisplayableCartoonSize.MEDIUM:
				this.source = cartoon.thumb;
				this.image.width = MEDIUM_WIDTH;
				
				// Textual information
				var information = $('<div></div>' )
					.append( $('<p class="title">'+cartoon.title+'</p>') )
					.append( $('<p class="author">'+cartoon.author+'</p>') )
					.append( $('<p class="date">'+cartoon.publicationDate+'</p>') );
					
				var monMedia =  $('<div class="media"></div>');
				monMedia.append( this.image  )
						.append( $('<div class="shape"></div>'));
					
				var monLi = $('<li style="display: list-item;"></li>' )
					.append( monMedia )
					.append( $('<div class="info"></div>').append(information) );
					
				// append all				
				this.$element
					.append( monLi );	
				break;
			
			case cimd.view.DisplayableCartoonSize.SMALL:
			default:
				
				this.image.width = SMALL_WIDTH;
				// Textual information
				var information = $('<div class="information"></div>' );
				information.append( $('<div class="title">'+cartoon.title+'</div>') )
					.append( $('<div class="author">'+cartoon.author+'</div>') )
					.append( $('<div class="date">'+cartoon.publicationDate+'</div>') );
					
					// append all				
				this.$element
					.append( '<div class="cartoonMark"></div>' )
					.append( this.image )
					.append( information );	
		
				break;
		}
		
	};
	
	DisplayableCartoon.prototype.appendTo = function( container ) {
		$(container).append( this.$element );
	};
	// TODO think about a better way to load src
	DisplayableCartoon.prototype.load = function( onload ){
		if (onload) {
			this.image.onload = onload;
			this.image.onerror = function(){
				trace( onload );
				// TODO  process
				onload();
			};
		}
		this.image.src = this.source;// load image
	};
	

	window.cimd.view.DisplayableCartoon = DisplayableCartoon;
	
	window.cimd.view.DisplayableCartoonSize = {
		LARGE : 0,
		MEDIUM : 1,
		SMALL : 2
	};
})();
(function() {
	
	function Feeds( container ) {
		this.$c = $('#'+container);
		this.$c.empty().append('<ul id="feeds"></ul>');
	};
	
	Feeds.prototype.appendAll = function( cs ) {
		var s = this;
		for (var i = 0, l = cs.length; i < l; i++) {
			s._append( cs[i], false );
		}
		
		//$('.title').widthTruncate();
	};

	Feeds.prototype.append = function( c ) {
		var self = this;
		// TODO slide the block
		this.$c.find('li:last').animate(
			{'height':0},
			1000,
			'linear',
			function() {
				self._append( c, true );
				$(this).remove();
				//$('.title').widthTruncate();
			}
		);
		
	};
	
	Feeds.prototype._append = function( c, e ) {
		// add the new one
		
		
		var $el = $('<li><div class="media"><img src="'+c.thumb+'" width="70" height="70" /><div class="shape"></div></div><div class="info"><div><p class="title">'+ c.title + '</p><p class="author">'+  c.author + ' - ' + c.date + '</p><p class="theme">'+ c.theme  + '</p></div></div></li>').hide();
		
		this.$c.prepend( $el );
		if( e ){
			$el.fadeIn('slow');	
		} else {
			$el.show();
		}
	};
	
	window.cimd.view.Feeds = Feeds;

})();

// MAIN CONTROLLER:
(function() {
	
	var events = cimd.global.customEvent;
	var firstLaunch = true;
	
	var _paymentManager = null;
	var _storeManager = null;
	var _libraryController = null;
	var _stripController = null;
	
	var _library = null;
	
	var _stripView = null;
	var _storeView = null;
	
	var _localData = null;	
	var _feedController = null;
	var process = {
		'strip' : true
	};
	
	var _defaultCurrency = window.common.currency.EUR;
	
	function CMMainController(){
		$.ajaxSetup({cache: false});
		this.connectedUser = null;
		// inherit from Observer
    	Observer.call(this);
	};
	Inheritance.extend( CMMainController, Observer );
	
	// callback script handler 
	// cf http://www.xml.com/pub/a/2005/12/21/json-dynamic-script-tag.html
	CMMainController.prototype.feedUpdateCallback = function(data) {
		_feedController.updateFeeds( data );
	};

	CMMainController.prototype.init = function( mode ) 
	{	
		var s = this;
		// disconnect if session expired
		window.cimd.ajaxHelper.addListener( events.common.ERROR_LOADING_DATA, function(event) {
			if( event.error == 'sessionExpired' ) {
				alert('Votre session a expirée');

				// logout with message, call the index
				s.logout();
			}
		});
		
		switch( mode ) {
			
			case 'HOME':
			
				_feedController = new window.cimd.controller.FeedController(null, 5);
				this.addListener( events.connection.CONNECT, function() {
					trace( 'connection handler' );
					// reload the page:
					window.location.href="";
				});
				this.addListener( events.connection.DISCONNECT, disconnectionHandler );
				this.addListener( events.connection.BAD_LOGIN, badLoginHandler );
				
				break;
				
			case 'LIBRARY':
			
				var self=this;

				this._initStore();
				this._initLibraryController();
				this._initStripController();

				var self = this;
				// library display
				
				this.addListener( 'libraryupdated', 
					function(event) 
					{
						if( event.hasOwnProperty('library') ) {
							//trace('isFirstLoad' event.firstload );
							if (event.hasOwnProperty('firstload') && event.firstload == true) {
								cimd.view.library.display(event.library);
							} else {
								cimd.view.library.update(event.library);
							}
							
							cimd.view.library.initControllerView(
								event.currentPage, event.pageCount 
							);
							
						}
					}
				);
				// update strip too
				this.addListener( 'libraryupdated', function(event) {
					
					_stripController.goTo( 0,
						event.library, 
						cimd.global.STRIP_ITEM_COUNT	
					);
				});
				
				cimd.view.library.addListener( events.views.LIST_ITEM_CLICK , function(event) {
					self.goToStripOfCartoons( event.itemindex );
				});
				
				
				cimd.view.controller.userPanelController.init();
				
				// Connection handler:
				this.addListener( events.connection.CONNECT, function() {
					trace( 'connection handler' );
					// reload the page:
					window.location.href="";
					//cimd.controller.main.displayLibrary( true );
				});
				this.addListener( events.connection.DISCONNECT, disconnectionHandler );
				this.addListener( events.connection.BAD_LOGIN, badLoginHandler );
				
				break;
				
			case 'ACCOUNT':
			
				// fields validator
				window.cimd.service.fieldsValidator.addListener( 
					events.validator.INVALID, invalidFieldHandler );
				window.cimd.service.fieldsValidator.addListener( 
					events.validator.VALID, validFieldHandler );
				
				this.addListener( events.connection.CONNECT, function() {
					trace( 'connection handler' );
					// reload the page:
					// check if it's connection comes from
					window.location.href="/signup/preapproved.php";
					//cimd.controller.main.displayLibrary( true );
				});
				this.addListener( events.connection.DISCONNECT, disconnectionHandler );
				//this.addListener( events.connection.BAD_LOGIN, badLoginHandler );
				
				break;
		}
	};
	
	//////////
	// INIT:
	
	// init services
	CMMainController.prototype._initStore = function() {	
		var s = this;
		_storeView = new cimd.view.store.ComplexStore(null);
		_storeView.addListener( events.store.REQUEST_PREAPPROVED_PLAN, function( event ) {
			s.preapprovedMe( event.data );
		});
		_storeView.addListener( events.store.ADD_SUBSCRIPTION_REQUEST, function( event ) {
			s.addSubscription( event.data );
		});

		$('#btn-showStore').click(
			function() {
				if( $(this).hasClass('on') ) {
					window.cimd.controller.main.hideStore();
					$(this).removeClass('on').addClass('off');
					$(this).removeClass("hide-store");
				} else {
					window.cimd.controller.main.displayStore();
					
					$(this).removeClass('off').addClass('on');
					$(this).addClass("hide-store");
				}
				return false;
			}
		);

		_paymentManager = new cimd.service.PaymentManager();
		
		// 
		
		_storeManager = new cimd.service.StoreManager();
		_storeManager.addListener( events.common.COMPLETE, dataStoreLoadedHandler );
		_storeManager.addListener( events.store.SUBSCRIPTION_ADDED, function() {
			// SUBSCRIPTION_ADDED
			_storeView.setWaiting( false );
			_storeManager.getSubscriptions( s.connectedUser );
		});
		
		_storeManager.addListener( events.common.ERROR_LOADING_DATA, dataStoreLoadingFailedHandler );
		_storeManager.addListener( events.store.PAYMENT_ERROR, function(event){
			_storeView.setWaiting(false);
			paymentFailedHandler(event);
		});
		
	};
	
	CMMainController.prototype._initLibraryController = function() {	
		_libraryController = new cimd.view.controller.LibraryController(0,12);
		_libraryController.addListener( events.common.COMPLETE, libraryLoadedHandler );
		_libraryController.addListener( events.common.ERROR_LOADING_DATA, libraryLoadingFailedHandler );
	};
	
	CMMainController.prototype._initStripController = function() {
		var self=this;
		_stripView = new cimd.view.StripView();
		_stripView.addListener( events.views.REQUESTED_STRIP_COMPLETED ,function() {
			process.strip = true;
		});
		
		////////////////////
		// Strip Controller
		_stripController = new cimd.view.controller.StripController();
		_stripController.addListener( events.actions.LIBRARY_LOAD_REQUESTED, function( event ) {
			var backward = ( event.data.direction != 'next' );
			self.displayLibrary( backward ); // request the next library, next strip follow this call by event
		
		});
		_stripController.addListener( events.actions.NEXT_STRIP_REQUESTED, function( event ) {
			if( process.strip == true ) {
				process.strip = false;
				// display the next strip
				_stripView.slideAndDisplayNext( event.data );
			}	
		});
		_stripController.addListener( events.actions.PREVIOUS_STRIP_REQUESTED, function( event ) {
			if( process.strip == true ) {
				process.strip = false;
				// display previous strip
				
				_stripView.slideAndDisplayPrevious( event.data );
			}	
		});
		///////////////////////
	};
	///////////
	
	CMMainController.prototype.setUser = function( user ) 
	{
		var s = this;
		this.connectedUser = user;
		this.displayLibrary( true );
		var c = $("#cm-userPanel");
		c.append( $('<span>'+this.connectedUser.linkedEmail+'&nbsp;</span>') );
		c.append( $('<a href="#">Se déconnecter</a>').click( 
			function() {
				s.logout();
			} 
		));
	};
	
	CMMainController.prototype.logWithXMLData = function(xmlData) {
		try {
			var user = new window.cimd.model.User( xmlData );
			this.setUser( user );
		} catch( e ) {
			// TODO Manage error
			trace( e );
		}
	};
	
	CMMainController.prototype.autoLogin = function() 
	{
		var s = this;
		// try to auconnect
		window.cimd.service.userManager.autoConnect(
			{
				success : function( user ) 
				{
					s.connectedUser = user;
					s.fire( events.connection.CONNECT );
				},
				error: function(errorType) {
					s.logout();
				}
			}
		);
	};
	/* form of the login */
	CMMainController.prototype.login = function( form ) 
	{
		var data = window.cimd.service.fieldsValidator.check( form );
		if( data ) {

			this.addListener( events.connection.BAD_LOGIN, aveComicsLoginBagLoginHandler );
			this._login( data.email, data.password, data.rememberme );
		}
	};
	
	CMMainController.prototype._login = function( email, password, rememberMe ) 
	{
		trace('main controller# login '+email + ' '+password);
		rememberMe = rememberMe || false;
		var self = this;
		
		var mp = ( password ) ? md5( password ):'';
		
		var spinner = $('form .spinner');
		spinner.css("visibility","visible");

		window.cimd.service.userManager.connect(
			email, mp, rememberMe,
			{
				success : function( user ) 
				{
					self.connectedUser = user;
					self.fire( events.connection.CONNECT );
				},
				
				error : function( errorType ) 
				{
					spinner.css("visibility","hidden");
					
					trace('Main#login - connection failed : ' + errorType );
					var message = null;
					if( errorType == 'connectionfailed' ) {
						message = 'Les identifiants utilisés sont incorrects';
					} else
					if( errorType == 'usernotlinked' ) {
						message = 'Utilisateur non lié';
						// TODO User linkage:
						//
						// - propose to create a new lib for this user
						// - propose to link with a mobile ( with CIMD )
					}
					if( errorType == 'timeout' ) {
						message = 'Le serveur ne répond pas, veuillez réessayer';
					}
					var event = {
						type: events.connection.BAD_LOGIN,
						message : message					
					};
					self.fire( event );
				}
			}
		);
	};
		
	CMMainController.prototype.logout = function( message, email ) 
	{
		trace( this );
		trace('main controller# logout');
		var event = {
			type : events.connection.DISCONNECT,
			message : message,
			email : email
		};
		this.fire( event );
	};
	
	CMMainController.prototype.createAccount = function( form ) 
	{
		var data = window.cimd.service.fieldsValidator.check( form );
		if( data ) 
		{
			this.addListener( events.connection.BAD_LOGIN, createAccountBagLoginHandler );
			window.cimd.service.userManager.createUser(
				data.email,
				data.password,
				{
					complete : function( state ){
						userCreationCompleteHandler.call( 
							this, state, data.email, data.password 
						);
					},
					error : userCreationFailedHandler
				}
			);
		}
	};
		
	CMMainController.prototype.displayLibrary = function( backward ) 
	{		
		if( process.strip == true ) 
		{
			backward = backward || false;
			trace('main controller# displayLibrary');
			if( this.connectedUser ) 
			{
				_libraryController.getCartoons(
					firstLaunch, this.connectedUser, backward
				);
			}
		}
	};
	
	// Banners of cartoons
	CMMainController.prototype.nextStripOfCartoons = function() {
		_stripController.next( _library, cimd.global.STRIP_ITEM_COUNT );
	};
	
	CMMainController.prototype.previousStripOfCartoons = function() {
		_stripController.previous( _library, cimd.global.STRIP_ITEM_COUNT );
	};
	
	CMMainController.prototype.goToStripOfCartoons = function( itemNum ) {
		_stripController.goTo( itemNum, _library, cimd.global.STRIP_ITEM_COUNT );
	};
	
	CMMainController.prototype.setCurrency = function(currency) {
		_defaultCurrency = currency || null;
	};
	
	CMMainController.prototype.displayStore = function() {
		
		trace('main controller# displayStore');
		var self = this;
		checkConnection(
			this.connectedUser,
			function() {
				_storeManager.getSubscriptions(
					self.connectedUser
				);
			}
		);
	};
	
	CMMainController.prototype.hideStore = function() {
		trace('main controller# hideStore');
		_storeView.hide();//call the view directly
	};
	
	CMMainController.prototype.renewSubscription = function(subscription) {
		trace('main controller# renewSubscription');
		
		_storeView.setWaiting( true );
		
		var self = this;
		checkConnection( 
			this.connectedUser, 
			function() {
				_storeManager.renewSubscription( 
					self.connectedUser,
					subscription
				);
			}
		);
	};
	
	CMMainController.prototype.addSubscription = function(subscription) {
		trace('main controller# addSubscription');
		_storeView.setWaiting( true );
		var self = this;
		checkConnection( 
			this.connectedUser, 
			function() {
				_storeManager.renewSubscription( 
					self.connectedUser,
					subscription
				);
			}
		);
	};
	//window.cimd.controller.main.requestAPreapprovalPayment()
	CMMainController.prototype.requestAPreapprovalPayment = function() {
		trace('main controller# ' + arguments.callee.name );
		_storeView.display('explanation','store-explanation'); //displayPreapprovalRequestPanel();
	};
	
	CMMainController.prototype.preapprovedMe = function(data){
		trace('main controller# '+arguments.callee.name );
		var self = this;
		checkConnection( 
			this.connectedUser, 
			function() {			
				_paymentManager.requestPreapproval(
					self.connectedUser,
					data
				);
			}
		);
	};
	
	CMMainController.prototype.data = function() {
		return _localData;
	};
	
	//////////////////////////////////////
	// CONNECTION / DISCONNECTION HANDLERS
	function checkConnection( user, handler ) 
	{
		if ( user ) {
			if( handler ) {
				handler();
			}
		} else {
			// no connection
			// TODO display a message, recall after connection ?
			trace("Not connected");
		}	
	};
	
	function disconnectionHandler(event) 
	{
		trace( 'disconnection handler' );
		// reload the page:
		// TODO spinner
		setTimeout( function() {
			window.cimd.service.userManager.disconnect();
		},100);
		//firstLaunch = true;
		
	};
	
	function createAccountBagLoginHandler(event) {
		// event.message
		event.target.removeListener( events.connection.BAD_LOGIN, createAccountBagLoginHandler );
		$( '#creationBoxMessage' ).addClass('error').empty().hide().text( 'Un compte avec le même email existe déjà' ).fadeIn();
	};
	
	function aveComicsLoginBagLoginHandler(event) {
		event.target.removeListener( events.connection.BAD_LOGIN, aveComicsLoginBagLoginHandler );
		$( '#connexionBoxMessage' ).addClass('error').empty().hide().text( 'Les identifiants utilisés sont incorrects' ).fadeIn();
	};
	
	function badLoginHandler(event) {
		trace( 'badlogin handler ' + event.message );
		$( '#message' ).addClass('error').empty().hide().text(event.message).fadeIn();
	};
	
	////////////
	// LIBRARY
	function libraryLoadingFailedHandler( event ) {
		if( event.error == 'sessionExpired' ) {
			// logout with message, call the index
			cimd.controller.main.logout();
			//libraryLoadingFailedHandler
			
		} else {

		}
	};
	
	function libraryLoadedHandler( event ) 
	{
		trace( event );
		if( event && event.hasOwnProperty('action') ) 
		{
			// INIT, Cartoons, Authors, Categories...
			if( event.action = 'init' ) {
				if( event.hasOwnProperty('data') ) {
					if ( event.data.hasOwnProperty('local') ) {
						trace('INIT local data');
						_localData = event.data.local;
					}
				}
			}
			// CARTOONS only
			if( event.hasOwnProperty('data') ) 
			{
			
				if( event.data.hasOwnProperty('library') ) 
				{
					// TODO Ensure _localData coherence 
					// Create a new Event
					_library = event.data.library; // update library
					if( _library && _library.cartoons.length > 0 )  
					{
						_stripController.reset();
						var e = {
							type : 'libraryupdated',
							library: event.data.library,
							firstload: firstLaunch,
							currentPage : event.data.currentPage,
							pageCount : event.data.pageCount
						};
						cimd.controller.main.fire( e );
					} else {
						// display the main store:
						cimd.controller.main.fire( {
							type : 'newuser'
						} );
						// cimd.controller.main.fire( e );
					}
				}
			}
		}
		firstLaunch = false;
	};
	
	//////////
	// STORE:
	function dataStoreLoadedHandler( event ) 
	{
		trace(event);
		if( event.hasOwnProperty('action') ) 
		{
			switch( event.action ) {
				case 'addSubscription' :
					// loader
					
					
					// addSubscription
					
					break;
					
				case 'getSubscriptions' :
					
					// Update the view
					var p = event.data.personal;
					var a = event.data.available;
					_storeView.setCurrency( _defaultCurrency );
					_storeView.load(
						
						'cm-content-store',
						function() 
						{ 
							if( p ) {
								$(p).each(
									function() {
										_storeView.addOwnSubscription(this);
									}
								);
							}
							if( a ) {
								for( var i=0,len=a.length;i<len;i++ ) {
									_storeView.addAvailableSubscription(a[i]);
								}
							}
							_storeView.show();	
						}
					);
					break;
			}
		}
	};
	
	function dataStoreLoadingFailedHandler( event ) 
	{
		//_storeView.show( );
		var action = null;
		if( event.hasOwnProperty('action') ) 
		{
			switch (action) {
				case 'addSubscription':
					// loader
					
					
					// addSubscription
					
					break;
					
				case 'getSubscriptions':
					
					break;
			}
				
		}
	};
	
	function paymentFailedHandler( event ) 
	{
		if( event.hasOwnProperty('error') ) {
			switch( event.error ) {
				case 'obsoletepreapproval':
					// then move to page
					window.cimd.controller.main.requestAPreapprovalPayment();
					break;
				case 'amountlimit':
					// then move to page
					var message = "<p></p>";
					_storeView.display('explanation', 'store-error-amount-exceeded');
					break;
				case 'preapprovalexpiration':
					var message = "<p></p>";
					_storeView.display('explanation', 'store-error-expiration');
					break;
				// TODO: error affine
				default:
					var message = "<p></p>";
					_storeView.display('explanation', 'store-error-payment-failed');
					break;
			}
		} 
	};
	
	// FORM AND FIELDS:
	function validFieldHandler( event ) 
	{
		var $field = event.data;
		if( $field.attr('type') == 'checkbox' ) return;
		// remove error message
		$field.parent().find('.error').remove();
		if ( $field.parent().find('.checked').length == 0 ) {
			$field.after( // wrap the span prevent the block display affected to the original span
				$('<span class="checked"><div class="checkedIcon"></div></span>')
					/*.wrap('<span></span>')*/
					.hide()
					.fadeIn(300)
			);
		}
	};
	
	function invalidFieldHandler( event ) 
	{
		var $field = event.data;
		if( $field.attr('type') == 'checkbox' ) return;
		var m = null;
		switch( $field.attr('name') ) {
			case 'email':
				m = "l'email renseigné n'est pas valide"; 
				break;
			case 'password':
				m = "le mot de passe doit être renseigné";
				break;
			case 'passwordRetype':
				m = "le mot de passe ne correspond pas";
				break;
		}
		if (m) {
			$field.parent().find('.checked').remove();
			if ( $field.parent().find('.error').length > 0 ) {
				
			}
			else {
				$field.after(	// wrap the span prevent the block display affected to the original span
					$('<span class="error" style="display:block">' + m + '</span>')
						/*.wrap('<span></span>')*/
						.hide()
						.fadeIn(300)
				);
			}
		}
	};
	
	function userCreationCompleteHandler(state,email,password) {
		// user created, reload the page
		if( state == 'accountalreadyset' ) {
			//self.fire( events.connection.CONNECT );
		} else {
			// connect
			
		}
		window.cimd.controller.main._login(email, password, false);
	};
	
	function userCreationFailedHandler() {
		// --> display an error message
	};
	
	window.cimd.controller.main = new CMMainController();
	window.Cimd = function( mode ) {
		window.cimd.controller.main.init( mode );
		return window.cimd.controller.main;
	};
})();
// MAIN CONTROLLER:
var _storeView = null;
var _library = null;
(function() {
	
	var events = cimd.global.customEvent;
	var firstLaunch = true;
	
	var _paymentManager = null;
	var _storeManager = null;
	var _libraryController = null;
	var _stripController = null;
	
	var _stripView=null;
	
	var _defaultCurrency = null;
	
	var _localData = null;	
	
	var process = {
		'strip' : true
	}
	
	function CMAccountController() {
		trace('constructor');
		this.state = null;
		// inherit from Observer
    	Observer.call(this);
	};
	Inheritance.extend( CMAccountController, Observer );

	CMAccountController.prototype.init = function( mode ) 
	{	
		var s = this;
		// disconnect if session expired
		window.cimd.ajaxHelper.addListener( events.common.ERROR_LOADING_DATA, function(event) {
			if( event.error == 'sessionExpired' ) {
				// logout with message, call the index
				s.logout();
			}
		});
		this.state = mode;
		switch( mode ) {

			case 'ACCOUNT':
			
				// fields validator
				window.cimd.service.fieldsValidator.addListener( 
					events.validator.INVALID, invalidFieldHandler );
				window.cimd.service.fieldsValidator.addListener( 
					events.validator.VALID, validFieldHandler );
				
				this.addListener( events.connection.CONNECT, function() {
					trace( 'connection handler' );
					// reload the page:
					// check if it's connection comes from
					window.location.href="/signup/preapproved.php";
				});
				this.addListener( events.connection.DISCONNECT, disconnectionHandler );
				
				
				break;
		
			case 'PREAPPROVED':
			
				cimd.view.controller.userPanelController.init();
				
				var s = this;
				_paymentManager = new cimd.service.PaymentManager({
					onsuccess : 'http://www.cairamieuxdemain.com/signup/store.php', 
					onfailed : 'http://www.cairamieuxdemain.com/signup/store.php'
				});				
				_storeView = new cimd.view.store.SimpleStore();
				_storeView.addListener( events.store.REQUEST_PREAPPROVED_PLAN, function( event ) {
					trace( event.data );
					s.preapprovedMe( event.data );
				});
				_storeView.load();
				
				this.addListener( events.connection.DISCONNECT, disconnectionHandler );

				break;
				
		
			case 'STORE':
				var self = this;
				cimd.view.controller.userPanelController.init();
				
				this._initLibraryController();
				
				// cm-main-store				
				_storeView = new cimd.view.store.SimpleStore(null);
		
				_paymentManager = new cimd.service.PaymentManager();
				
				_storeManager = new cimd.service.StoreManager();
				_storeManager.addListener( events.common.COMPLETE, dataStoreLoadedHandler );
				_storeManager.addListener( events.store.SUBSCRIPTION_ADDED, function() {
					// SUBSCRIPTION_ADDED
					window.location.href=""; // go to main page
					
				});
				_storeManager.addListener( events.common.ERROR_LOADING_DATA, dataStoreLoadingFailedHandler );
				_storeManager.addListener( events.store.PAYMENT_ERROR, paymentFailedHandler );
				
				// RENEW SUBSCRIPTION
				_storeView.addListener( events.store.REQUEST_PREAPPROVED_PLAN, function( event ) {
					s.preapprovedMe( event.data );
				});
				_storeView.addListener( events.store.ADD_SUBSCRIPTION_REQUEST, function( event ) {
					s.addSubscription( event.data );
				});

				this.addListener( events.connection.DISCONNECT, disconnectionHandler );

				break;
		}
	};
	
	//////////
	// INIT:
	
	// init services
	CMAccountController.prototype._initStore = function() {	
		var s=this;
		_storeView = new cimd.view.store.ComplexStore(null);

		$('#btn-showStore').click(
			function() {
				if( $(this).hasClass('on') ) {
					s.hideStore();
					$(this).removeClass('on').addClass('off');
					$(this).removeClass("hide-store");
				} else {
					s.displayStore();
					$(this).removeClass('off').addClass('on');
					$(this).addClass("hide-store");
				}
				return false;
			}
		);

		_paymentManager = new cimd.service.PaymentManager();
		
		_storeManager = new cimd.service.StoreManager();
		_storeManager.addListener( events.common.COMPLETE, dataStoreLoadedHandler );
		_storeManager.addListener( events.common.ERROR_LOADING_DATA, dataStoreLoadingFailedHandler );
		_storeManager.addListener( events.store.PAYMENT_ERROR, paymentFailedHandler );
	};
	
	CMAccountController.prototype._initLibraryController = function() 
	{	
		_libraryController = new cimd.view.controller.LibraryController(0,14);
		_libraryController.addListener( events.common.COMPLETE, libraryLoadedHandler );
		_libraryController.addListener( events.common.ERROR_LOADING_DATA, libraryLoadingFailedHandler );
	};
	
	CMAccountController.prototype._initStripController = function() 
	{
		var self=this;
		
		_stripView = new cimd.view.StripView();
		_stripView.addListener( events.views.REQUESTED_STRIP_COMPLETED ,function() {
			process.strip = true;
		});
		
		////////////////////
		// Strip Controller
		_stripController = new cimd.view.controller.StripController();
		_stripController.addListener( events.actions.LIBRARY_LOAD_REQUESTED, function( event ) {
			var backward = ( event.data.direction != 'next' );
			self.displayLibrary( backward ); // request the next library, next strip follow this call by event
		
		});
		_stripController.addListener( events.actions.NEXT_STRIP_REQUESTED, function( event ) {
			if( process.strip == true ) {
				process.strip = false;
				// display the next strip
				_stripView.slideAndDisplayNext( event.data );
			}	
		});
		_stripController.addListener( events.actions.PREVIOUS_STRIP_REQUESTED, function( event ) {
			if( process.strip == true ) {
				process.strip = false;
				// display previous strip
				
				_stripView.slideAndDisplayPrevious( event.data );
			}	
		});
		///////////////////////
	};
	///////////
	
	CMAccountController.prototype.setUser = function( user ) {
		var s = this;
		this.connectedUser = user;
		var c = $("#cm-userPanel");
		c.append( $('<span>'+this.connectedUser.linkedEmail+'&nbsp;</span>') );
		c.append( $('<a href="#">Se déconnecter</a>').click( 
			function() {
				s.logout();
			} 
		));
	};
	
	CMAccountController.prototype.logWithXMLData = function(xmlData) {
		try {
			
			var user = new window.cimd.model.User( xmlData );
			this.setUser( user );
		
		} catch( e ) {
			// TODO Manage error
			trace( e );
		}
	};
	
	CMAccountController.prototype.autoLogin = function() 
	{
		var s = this;
		// try to auconnect
		window.cimd.service.userManager.autoConnect(
			{
				success : function( user ) 
				{
					s.connectedUser = user;
					s.fire( events.connection.CONNECT );
				},
				error: function(errorType) {
					s.logout();
				}
			}
		);
	};
	/* form of the login */
	CMAccountController.prototype.login = function( form ) 
	{
		var data = window.cimd.service.fieldsValidator.check( form );
		if( data ) {
			this._login( data.email, data.password, data.rememberme );
		}
	};
	
	CMAccountController.prototype._login = function( email, password, rememberMe ) 
	{
		trace('main controller# login '+email + ' '+password);
		rememberMe = rememberMe || false;
		var self = this;
		
		var mp = ( password ) ? md5( password ):'';
		
		var spinner = $('form .spinner');
		spinner.css("visibility","visible");

		window.cimd.service.userManager.connect(
			email, mp, rememberMe,
			{
				success : function( user ) 
				{
					self.connectedUser = user;
					self.fire( events.connection.CONNECT );
				},
				
				error : function( errorType ) 
				{
					spinner.css("visibility","hidden");
					
					trace('Main#login - connection failed : ' + errorType );
					var message = null;
					if( errorType == 'connectionfailed' ) {
						message = 'Mauvais identifiants';
					} else
					if( errorType == 'usernotlinked' ) {
						message = 'Utilisateur non lié';
						// TODO User linkage:
						//
						// - propose to create a new lib for this user
						// - propose to link with a mobile ( with CIMD )
					}
					if( errorType == 'timeout' ) {
						message = 'timeout'; // TODO translate
					}
					var event = {
						type: events.connection.BAD_LOGIN,
						message : message					
					};
					self.fire( event );
				}
			}
		);
	};
		
	CMAccountController.prototype.logout = function( message, email ) 
	{
		trace( this );
		trace('main controller# logout');
		var event = {
			type : events.connection.DISCONNECT,
			message : message,
			email : email
		};
		this.fire( event );
	};
	
	CMAccountController.prototype.createAccount = function( form ) 
	{
		var data = window.cimd.service.fieldsValidator.check( form );
		if( data ) 
		{
			this.addListener( events.connection.BAD_LOGIN, createAccountBagLoginHandler );
			window.cimd.service.userManager.createUser(
				data.email,
				data.password,
				{
					complete : function( state ){
						userCreationCompleteHandler.call( 
							this, state, data.email, data.password 
						);
					},
					error : userCreationFailedHandler
				}
			);
		}
	};
		
	CMAccountController.prototype.displayLibrary = function( backward ) 
	{		
		if( process.strip == true ) 
		{
			backward = backward || false;
			trace('main controller# displayLibrary');
			if( this.connectedUser ) 
			{
				_libraryController.getCartoons(
					firstLaunch, this.connectedUser, backward
				);
			}
		}
	};
	
	// Banners of cartoons
	CMAccountController.prototype.nextStripOfCartoons = function() {
		_stripController.next( _library, cimd.global.STRIP_ITEM_COUNT );
	};
	
	CMAccountController.prototype.previousStripOfCartoons = function() {
		_stripController.previous( _library, cimd.global.STRIP_ITEM_COUNT );
	};
	
	CMAccountController.prototype.goToStripOfCartoons = function( itemNum ) {
		_stripController.goTo( itemNum, _library, cimd.global.STRIP_ITEM_COUNT );
	};
	
	CMAccountController.prototype.displayStore = function(currency) {
		_defaultCurrency = currency;
		trace('main controller# displayStore');
		var s = this;
		checkConnection(
			this.connectedUser,
			function() {
				_storeManager.getSubscriptions(
					s.connectedUser
				);
			}
		);
	};
	
	CMAccountController.prototype.hideStore = function() {
		trace('main controller# hideStore');
		_storeView.hide();//call the view directly
	};
	
	CMAccountController.prototype.renewSubscription = function(subscription) {
		trace('main controller# renewSubscription');
		var self = this;
		checkConnection( 
			this.connectedUser, 
			function() {
				_storeManager.renewSubscription( 
					self.connectedUser,
					subscription
				);
			}
		);
	};
	
	CMAccountController.prototype.addSubscription = function(subscription) {
		trace('main controller# addSubscription');
		_storeView.setWaiting( true );
		var self = this;
		checkConnection( 
			this.connectedUser, 
			function() {
				_storeManager.renewSubscription( 
					self.connectedUser,
					subscription
				);
			}
			
		);
	};
	//window.cimd.controller.main.requestAPreapprovalPayment()
	CMAccountController.prototype.requestAPreapprovalPayment = function() {
		trace('main controller# ' + arguments.callee.name );
		_storeView.display('explanation','store-explanation'); //displayPreapprovalRequestPanel();
	};
	
	CMAccountController.prototype.preapprovedMe = function(data){
		trace('main controller# '+arguments.callee.name );
		var self = this;
		checkConnection( 
			this.connectedUser, 
			function() {			
				_paymentManager.requestPreapproval(
					self.connectedUser,
					data
				);
			}
		);
	};
	
	CMAccountController.prototype.data = function() {
		return _localData;
	};
	
	//////////////////////////////////////
	// CONNECTION / DISCONNECTION HANDLERS
	function checkConnection( user, handler ) 
	{
		trace(user);
		if ( user ) {
			if( handler ) {
				handler();
			}
		} else {
			// no connection
			// TODO display a message, recall after connection ?
			trace("Not connected");
		}	
	};
	
	function disconnectionHandler(event) 
	{
		trace( 'disconnection handler' );
		// reload the page:
		// TODO spinner
		setTimeout( function() {
			window.cimd.service.userManager.disconnect();
		},500);
		//firstLaunch = true;
		
	};
	
	function createAccountBagLoginHandler(event) {
		trace( event );
	};

	function badLoginHandler(event) {
		trace( 'badlogin handler ' + event.message );
		$( '#message' ).addClass('error').empty().hide().text(event.message).fadeIn();
	};
	
	////////////
	// LIBRARY
	function libraryLoadingFailedHandler( event ) {
		if( event.error == 'sessionExpired' ) {
			// logout with message, call the index
			window.c.logout();
			//libraryLoadingFailedHandler
			
		} else {

		}
	};
	
	function libraryLoadedHandler( event ) 
	{
		trace( event );
		if( event && event.hasOwnProperty('action') ) 
		{
			// INIT, Cartoons, Authors, Categories...
			if( event.action = 'init' ) {
				if( event.hasOwnProperty('data') ) {
					if (event.data.hasOwnProperty('local')) {
						trace('INIT local data');
						_localData = event.data.local;
					}
				}
			}
			// CARTOONS only
			if( event.hasOwnProperty('data') ) 
			{
				if( event.data.hasOwnProperty('library') ) 
				{
					// TODO Ensure _localData coherence 
					// Create a new Event
					_library = event.data.library; // update library
					if( _library && _library.cartoons.length > 0 )  
					{
						_stripController.reset();
						var e = {
							type : 'libraryupdated',
							library: event.data.library,
							firstload: firstLaunch,
							currentPage : _localData.currentPage,
							pageCount : _localData.pageCount
						};
						cimd.controller.main.fire( e );
					} else {
						// display the main store:
						cimd.controller.main.fire( {
							type : 'newuser'
						} );
						// cimd.controller.main.fire( e );
					}
				}
			}
		}
		firstLaunch = false;
	};
	
	//////////
	// STORE:
	function dataStoreLoadedHandler( event ) 
	{
		if( event.hasOwnProperty('action') ) 
		{
			switch( event.action ) {
				case 'addSubscription' :
					// loader
					
					
					// addSubscription
					
					break;
					
				case 'getSubscriptions' :
					
					// Update the view
					var p = event.data.personal;
					var a = event.data.available;
					_storeView.setCurrency( _defaultCurrency );
					_storeView.load(
						
						'cm-content-store',
						function() 
						{ 
							if( p ) {
								$(p).each(
									function() {
										_storeView.addOwnSubscription(this);
									}
								);
							}
							if( a ) {
								for( var i=0,len=a.length;i<len;i++ ) {
									_storeView.addAvailableSubscription(a[i]);
								}
							}
							_storeView.show();	
						}
					);
					break;
			}
		}
	};
	
	function dataStoreLoadingFailedHandler( event ) 
	{
		trace( event );
		//_storeView.show( );
		var action = null;
		if( event.hasOwnProperty('action') ) 
		{

			

			switch (action) {
				case 'addSubscription':
					// loader
					
					
					// addSubscription
					
					break;
					
				case 'getSubscriptions':
					
					break;
			}
				
		}
	};
	
	function paymentFailedHandler( event ) 
	{
		trace( event.error );
		if( event.hasOwnProperty('error') ) {
			switch( event.error ) {
				case 'obsoletepreapproval':
					// then move to page
					window.cimd.controller.main.requestAPreapprovalPayment();
					break;
				case 'amountlimit':
					// then move to page
					var message = "<p></p>";
					_storeView.display('explanation', 'store-error-amount-exceeded');
					break;
				// TODO: error affine
				case 'timeout':
					_storeView.display('explanation', 'store-error-timeout');
					break;
				default:
					var message = "<p></p>";
					_storeView.display('explanation', 'store-error-payment-failed');
					break;
			}
		} 
	};
	
	// FORM AND FIELDS:
	function validFieldHandler( event ) 
	{
		var $field = event.data;
		if( $field.attr('type') == 'checkbox' ) return;
		// remove error message
		$field.parent().find('.error').remove();
		if ( $field.parent().find('.checked').length == 0 ) {
			$field.after( // wrap the span prevent the block display affected to the original span
				$('<span class="checked"><div class="checkedIcon"></div></span>')
					/*.wrap('<span></span>')*/
					.hide()
					.fadeIn(300)
			);
		}
	};
	
	function invalidFieldHandler( event ) 
	{
		var $field = event.data;
		if( $field.attr('type') == 'checkbox' ) return;
		var m = null;
		switch( $field.attr('name') ) {
			case 'email':
				m = "l'email renseigné n'est pas valide"; 
				break;
			case 'password':
				m = "le mot de passe doit être renseigné";
				break;
			case 'passwordRetype':
				m = "le mot de passe ne correspond pas";
				break;
		}
		if (m) {
			$field.parent().find('.checked').remove();
			if ( $field.parent().find('.error').length > 0 ) {
				
			}
			else {
				$field.after(	// wrap the span prevent the block display affected to the original span
					$('<span class="error" style="display:block">' + m + '</span>')
						/*.wrap('<span></span>')*/
						.hide()
						.fadeIn(300)
				);
			}
		}
	};
	
	function userCreationCompleteHandler(state,email,password) {
		trace( state );
		// user created, reload the page
		if( state == 'accountalreadyset' ) {
			//self.fire( events.connection.CONNECT );
		} else {
			// connect
			
		}
		//window.cimd.controller.main._login(email, password, false);
	};
	
	function userCreationFailedHandler() {
		// --> display an error message
	};
	
	window.CimdAccount = function( mode ) {
		var c = new CMAccountController();
		c.init( mode );
		return c;
	};
})();

