(function($,document){
    var o_llDateSelect = function(o_options){
        var
            o_settings = {
                'splitter':'-',
                'order':'y-m-d',
                'days':'Maandag,Dinsdag,Woensdag,Donderdag,Vrijdag,Zaterdag,Zondag',
                'months':'Januari,Februari,Maart,April,Mei,Juni,Juli,Augustus,September,Oktober,November,December',
                'className':'llDateSelect',
                'prevName':'<',
                'nextName':'>',
                'text':'[d] [M] [y]',
                'textId':'',
                'textValue':'[D] [d] [M] [m] [Y]',
                'hideInput':'y',

                'i_curDay':'',
                'i_curMonth':'',
                'i_curYear':''
            },
            i_curDay, i_curMonth, i_curYear,
            getVal = function(dv_item){
                var o_settings = getSettings(dv_item);
                var i_year = o_settings.i_curYear;
                var i_month = o_settings.i_curMonth+1;
                var i_day = o_settings.i_curDay.toString() != '' && o_settings.i_curDay != undefined ? o_settings.i_curDay+1 : '';
                var s_val = o_settings.order;
                i_year = i_year.toString();
                i_month = i_month.toString();
                i_day = i_day.toString();
                if(i_year == '' || i_month == '' || i_day == ''){
                    s_val = '';
                } else {
                    s_val = s_val.replace('y',i_year);
                    s_val = s_val.replace('m',i_month.length < 2 ? '0'+i_month : i_month);
                    s_val = s_val.replace('d',i_day != '' ? i_day.length < 2 ? '0'+i_day : i_day : '');
                }
                return(s_val);
            },
            clickDate = function(dv_item,dv_day){
                setDay(dv_item,o_settings.i_curDay.toString() != '' && o_settings.i_curDay != undefined && o_settings.i_curDay+1 == parseInt($(dv_day).html()) ? '' : parseInt($(dv_day).html()));
                setInput(dv_item);
                setDate(dv_item,$(dv_item).val());
            },
            clickMonth = function(dv_item,s_type){
                var o_settings = getSettings(dv_item);
                var i_month = o_settings.i_curMonth+1;
                var i_year = o_settings.i_curYear;
                if(s_type == 'prev'){
                    if(i_month == 1){
                        i_month = 12;
                        i_year--;
                    } else {
                        i_month--;
                    }
                } else {
                    if(i_month == 12){
                        i_month = 1;
                        i_year++;
                    } else {
                        i_month++;
                    }
                }
                setMonth(dv_item,i_month);
                setYear(dv_item,i_year);
                setInput(dv_item);
                setDate(dv_item,$(dv_item).val());
            },
            setDay = function(dv_item,i_day){
                var o_settings = getSettings(dv_item);
                o_settings.i_curDay = i_day == '' ? '' : parseInt(i_day*1)-1;
                if(isNaN(o_settings.i_curDay)){
                    var o_date = new Date();
                    o_settings.i_curDay = '';//o_date.getDate()-1;
                }
                setSettings(dv_item,o_settings);
                var o_dateStart = new Date();
                o_dateStart.setFullYear(o_settings.i_curYear,o_settings.i_curMonth,0);
                var i_dayStart = o_dateStart.getDay();
                var s_id = $(dv_item).attr('id');
                var dv_holder = $('#'+s_id+'_holder');
                var dv_holderDays = $('div[class="days"]',dv_holder);
                $('div',dv_holderDays).removeClass('cur').addClass('on');
                if(o_settings.i_curDay.toString() != '' && o_settings.i_curDay != undefined){
                    $('div',dv_holderDays).eq((i_dayStart+o_settings.i_curDay)+'').removeClass('on').addClass('cur');
                }
            },
            setMonth = function(dv_item,i_month){
                var o_settings = getSettings(dv_item);
                o_settings.i_curMonth = parseInt(i_month*1)-1;

                var i_dayTotal = daysInMonth(o_settings.i_curYear,o_settings.i_curMonth);
                if(o_settings.i_curDay.toString() != '' && o_settings.i_curDay+1 > i_dayTotal){
                    o_settings.i_curDay = i_dayTotal-1;
                }

                if(isNaN(o_settings.i_curMonth)){
                    var o_date = new Date();
                    o_settings.i_curMonth = o_date.getMonth();
                }
                setSettings(dv_item,o_settings);
                var s_id = $(dv_item).attr('id');
                var dv_holder = $('#'+s_id+'_holder');
                var dv_holderTopMonths = $('div[class="topMonths"]',dv_holder);
                $('div[class="month"]',dv_holderTopMonths).hide();
                $('div[class="month"]',dv_holderTopMonths).eq(o_settings.i_curMonth).show();
            },
            setYear = function(dv_item,i_year){
                var o_settings = getSettings(dv_item);
                o_settings.i_curYear = parseInt(i_year*1);
                if(isNaN(o_settings.i_curYear)){
                    var o_date = new Date();
                    o_settings.i_curYear = o_date.getFullYear();
                }
                setSettings(dv_item,o_settings);
                var s_id = $(dv_item).attr('id');
                var dv_holder = $('#'+s_id+'_holder');
                $('div[class="topYear"]',dv_holder).html(o_settings.i_curYear);
            },
            setInput = function(dv_item){  
                $(dv_item).val(getVal(dv_item)).change();
            },
            setAction = function(dv_item){
                $(dv_item).change(function(){
                    setDate(this,$(this).val());
                }).keyup(function(){
                    setDate(this,$(this).val());
                });
            },
            setDate = function(dv_item,s_date){
                var o_settings = getSettings(dv_item);
                var a_dateOrder = o_settings.order.split(o_settings.splitter);
                var i_dateOrder = 0;
                if(s_date == '' || s_date == undefined){
                    var o_date = new Date();
                    while(i_dateOrder < a_dateOrder.length){
                        if(s_date != ''){
                            s_date += o_settings.splitter;
                        }
                        if(a_dateOrder[i_dateOrder] == 'y'){
                            s_date += o_date.getFullYear();
                        } else if(a_dateOrder[i_dateOrder] == 'm'){
                            s_date += o_date.getMonth()+1;
                        } else if(a_dateOrder[i_dateOrder] == 'd'){
                            s_date += 'n';//o_date.getDate();
                        }
                        i_dateOrder++;
                    }
                }
                var a_date = s_date.split(o_settings.splitter);
                var a_dateOrder2 = new Array('y','m','d');
                i_dateOrder = 0;
                var i_dateOrder2 = 0;
                var i_dateOrder2Check = 0;
                while(i_dateOrder2 < a_dateOrder2.length){
                    i_dateOrder2Check = 0;
                    i_dateOrder = false;
                    while(i_dateOrder2Check < a_dateOrder.length){
                        if(a_dateOrder[i_dateOrder2Check] == a_dateOrder2[i_dateOrder2]){
                            i_dateOrder = i_dateOrder2Check;
                            break;
                        }
                        i_dateOrder2Check++;
                    }
                    i_dateOrder2++;
                    if(a_dateOrder[i_dateOrder] == 'y' || a_dateOrder[i_dateOrder] == 'm' || a_dateOrder[i_dateOrder] == 'd' && a_date[i_dateOrder] != '' && a_date[i_dateOrder] != undefined){
                        if(a_dateOrder[i_dateOrder] == 'y'){
                            setYear(dv_item,a_date[i_dateOrder]);
                        } else if(a_dateOrder[i_dateOrder] == 'm'){
                            setMonth(dv_item,a_date[i_dateOrder]);
                        } else if(a_dateOrder[i_dateOrder] == 'd'){
                            setDay(dv_item,a_date[i_dateOrder]);
                        }
                    }
                }
                setHtml(dv_item);
            },
            setSettings = function(dv_item,o_settingsNew){
                var s_settings = '';
                if(o_settingsNew){
                    o_settings = o_settingsNew;
                }
                $.each(o_settings,function(s_key,i_val){
                    if(s_key == 'order'){
                        i_val = i_val.toLowerCase();
                    }
                    if(s_settings != ''){
                        s_settings += ',';
                    }
                    s_settings += '"'+s_key+'":';
                    if(typeof(i_val) == 'string'){
                        s_settings += '"';
                    }
                    s_settings += typeof(i_val) == 'number' ? isNaN(i_val) ? '""' : parseInt(i_val)*1 : i_val;
                    if(typeof(i_val) == 'string'){
                        s_settings += '"';
                    }
                });
                s_settings = '{'+s_settings+'}';
                $(dv_item).attr('settings',s_settings);
                var o_settings2 = $.parseJSON(s_settings);
            },
            getSettings = function(dv_item){
                return($.parseJSON($(dv_item).attr('settings')));
            },
            setHtml = function(dv_item){
                var o_settings = getSettings(dv_item);
                var s_id = $(dv_item).attr('id');
                var dv_holder = $('#'+s_id+'_holder');
                var dv_holderDays = $('div[class="days"]',dv_holder);

                var o_date = new Date();
                o_date.setFullYear(o_settings.i_curYear,o_settings.i_curMonth,0);
                var i_dayStart = o_date.getDay();
                var i_dayTotal = daysInMonth(o_settings.i_curYear,o_settings.i_curMonth);
                var b_started = false;
                var i_day = 0;
                var i_row = 0;
                var i_height = 0;
                $('div',dv_holderDays).each(function(i_index){
                    $(this).removeClass('cur off on');
                    if(i_index == i_dayStart){
                        b_started = true;
                    }
                    if(b_started){
                        if(i_day >= i_dayTotal){
                            if(i_row == 0 || i_row > 6){
                                i_row = 'n';
                            }
                            if(i_row == 'n'){
                                $(this).hide().html('').addClass('off');
                            } else {
                                $(this).show().html('').addClass('off');
                            }
                        } else {
                            $(this).show().html(i_day+1).addClass(i_day == o_settings.i_curDay && o_settings.i_curDay.toString() != '' && o_settings.i_curDay != undefined ? 'cur' : 'on');
                        }
                        i_day++;
                    } else {
                        $(this).show().html('').addClass('off');
                    }
                    if(i_row != 'n'){
                        if(i_row < 6){
                            i_row++;
                        } else {
                            i_height += $(this).outerHeight();
                            i_row = 0;
                        }
                    }
                });
                $(dv_holderDays).height(i_height);
                if(o_settings.text != '' && o_settings.text != undefined || o_settings.textValue != '' && o_settings.textValue != undefined){
                    var i_month = o_settings.i_curMonth+1;
                    i_day = o_settings.i_curDay.toString() != '' && o_settings.i_curDay != undefined ? o_settings.i_curDay+1 : '';
                    var s_val = o_settings.order;
                    i_month = i_month.toString();
                    i_day = i_day;
                    if(i_day != ''){
                        o_date = new Date();
                        o_date.setFullYear(o_settings.i_curYear,o_settings.i_curMonth,o_settings.i_curDay);
                        i_dayStart = o_date.getDay();
                        var a_days = o_settings.days.split(',');
                    }
                    var a_months = o_settings.months.split(',');
                    if(o_settings.textValue != '' && o_settings.textValue != undefined){
                        var s_textValue = o_settings.textValue;
                        s_textValue = s_textValue.replace('[y]',o_settings.i_curYear);
                        s_textValue = s_textValue.replace('[m]',i_month.length < 2 ? '0'+i_month : i_month);
                        s_textValue = s_textValue.replace('[d]',i_day != '' ? i_day.length < 2 ? '0'+i_day : i_day : '');
                        s_textValue = s_textValue.replace('[Y]',o_settings.i_curYear);
                        s_textValue = s_textValue.replace('[M]',a_months[o_settings.i_curMonth]);
                        s_textValue = s_textValue.replace('[D]',i_day != '' ? a_days[i_dayStart] : '');
                        $(dv_item).attr('textValue',s_textValue);
                    }
                    if(o_settings.text != '' && o_settings.text != undefined){
                        var s_text = o_settings.text;
                        s_text = s_text.replace('[y]',o_settings.i_curYear);
                        s_text = s_text.replace('[m]',i_month.length < 2 ? '0'+i_month : i_month);
                        s_text = s_text.replace('[d]',i_day != '' ? i_day.length < 2 ? '0'+i_day : i_day : '');
                        s_text = s_text.replace('[Y]',o_settings.i_curYear);
                        s_text = s_text.replace('[M]',a_months[o_settings.i_curMonth]);
                        s_text = s_text.replace('[D]',i_day != '' ? a_days[i_dayStart] : '');
                        $('div[class="text"]',dv_holder).html(s_text);
                    }
                }
            },
            createHtml = function(dv_item,i_index){
                var o_settings = getSettings(dv_item);
                if(o_settings.hideInput == 'y'){
                    $(dv_item).hide();
                }
                if($(dv_item).attr('id') == '' || $(dv_item).attr('id') == undefined){
                    $(dv_item).attr('id','llDateSelect_'+Math.floor(Math.random()*11)+'_'+i_index);
                }
                var s_id = $(dv_item).attr('id');
                $(dv_item).after('<div id="'+s_id+'_holder" class="'+o_settings.className+'"></div>');
                var dv_holder = $('#'+s_id+'_holder');
                if(o_settings.text != '' && o_settings.text != undefined){
                    $(dv_holder).append('<div class="text"></div>');
                }
                $(dv_holder).append('<div class="contentHolder"></div>');
                var dv_holderContentHolder = $('div[class="contentHolder"]',dv_holder);

                $(dv_holderContentHolder).append('<div class="topDays"></div>');
                $(dv_holderContentHolder).append('<div class="topMonths"></div>');
                $(dv_holderContentHolder).append('<div class="topYear"></div>');
                $(dv_holderContentHolder).append('<div class="days"></div>');

                var dv_holderTopDays = $('div[class="topDays"]',dv_holder);
                var dv_holderTopMonths = $('div[class="topMonths"]',dv_holder);
                var dv_holderDays = $('div[class="days"]',dv_holder);

                var a_days = o_settings.days.split(',');
                var i_day = 0;
                while(i_day < 7){
                    $(dv_holderTopDays).append('<div title="'+a_days[i_day]+'">'+a_days[i_day].substr(0, 1)+'</div>');
                    i_day++;
                }
                var a_months = o_settings.months.split(',');
                var i_month = 0;
                $(dv_holderTopMonths).append('<div class="prev">'+o_settings.prevName+'</div>');
                $(dv_holderTopMonths).append('<div class="next">'+o_settings.nextName+'</div>');
                while(i_month < 12){
                    $(dv_holderTopMonths).append('<div class="month" title="'+a_days[i_month]+'">'+a_months[i_month]+'</div>');
                    i_month++;
                }
                var i_rows = 0;
                var i_cols = 0;
                while(i_rows < 7){
                    i_cols = 0;
                    while(i_cols < 7){
                        $(dv_holderDays).append('<div'+(i_cols == 0 ? ' class="clear"' : '')+'></div>');
                        i_cols++;
                    }
                    i_rows++;
                }
                $('div',dv_holderDays).click(function(){
                    var dv_item = $('#'+$(this).parent().parent().parent().attr('id').replace('_holder',''));
                    clickDate(dv_item,this);
                });
                $('div[class="prev"], div[class="next"]',dv_holderTopMonths).click(function(){
                    var dv_item = $('#'+$(this).parent().parent().parent().attr('id').replace('_holder',''));
                    clickMonth(dv_item,$(this).attr('class'));
                }).dblclick(function(){
                    return(false);
                });
            },
            daysInMonth = function(i_year, i_month){
                return(32 - new Date(i_year, i_month, 32).getDate());
            }
        ;
        return this.each(function(i_index){
            o_options = $.extend({}, o_settings, o_options||{});
            $.extend(o_settings,o_options);
            setSettings(this,false);
            createHtml(this);
            setDate(this,$(this).val());
            setInput(this);
            setAction(this);
        });
    };
    var o_methods = {
        init:o_llDateSelect
    };
    $.fn.llDateSelect = function(method){
        if(o_methods[method]){
          return o_methods[method].apply(this,Array.prototype.slice.call(arguments,1));
        } else if(typeof(method) === 'object' || !method){
          return o_methods.init.apply(this,arguments);
        } else {
          $.error('Method '+ method+' does not exist on jQuery.llDateSelect');
        }
    };
})(jQuery,document);
