import fastformat from '../../core/strings/fastformat' ;

/**
 * Helper class to manipulates and formats the day of weeks expressions.
 * See the <a href="https://schema.org/DayOfWeek">https://schema.org/DayOfWeek</a> definition.
 * @name DayOfWeek
 * @memberof system.calendar
 * @class
 * @example
 * let dayOfWeek = new DayOfWeek() ;
 *
 * console.log( dayOfWeek.parse('Mo') ) ;
 * console.log( dayOfWeek.parse('Mo,Th,Ph') ) ;
 * console.log( dayOfWeek.parse('Mo-Th,Fr,Sa-Su,Ph,Sh') ) ;
 * console.log( dayOfWeek.format(['Ph','Sh'],true) ) ;
 */
class DayOfWeek
{
    /**
     * @constructor
     * @memberof system.calendar.DayOfWeek
     * @param {Object} init The generic object to initialize this instance.
     */
    constructor( init )
    {
        this.days     = [ 'Mo','Tu','We','Th','Fr','Sa','Su'] ;
        this.specials = [ 'Ph' , 'Sh' ] ;
        this.strings =
        {
            all     : 'Everyday' ,
            days    :
            [
                { id:'Mo' , name:"Monday"          , short:'Mo' } ,
                { id:'Tu' , name:"Tuesday"         , short:'Tu' } ,
                { id:'We' , name:"Wednesday"       , short:'We' } ,
                { id:'Th' , name:"Thursday"        , short:'Th' } ,
                { id:'Fr' , name:"Friday"          , short:'Fr' } ,
                { id:'Sa' , name:"Saturday"        , short:'Sa' } ,
                { id:'Su' , name:"Sunday"          , short:'Su' } ,
                { id:'Ph' , name:"Public holidays" , short:'Ph' } ,
                { id:'Sh' , name:"School holidays" , short:'Sh' }
            ],
            none     : '' ,
            specials : '{0} / {1}' ,
            week     : 'Working days' ,
            weekend  : 'Week end'
        };

        if( init )
        {
            for( let prop in init )
            {
                this[prop] = init[prop] ;
            }
        }
    }

    /**
     * Format the specific days representation.
     * @param {Array} days
     * @param {boolean} humanReadble
     * @memberof system.calendar.DayOfWeek
     * @function
     * @returns {String} The formatted representation of the days of week.
     */
    format( days , humanReadble = false )
    {
        let exp = '' ;

        if( !days || !(days instanceof Array) || days.length === 0 )
        {
            return (humanReadble === true) ? this.strings.none : '' ;
        }

        let i ;
        let cur ;
        let pre ;
        let pos ;

        let len = days.length ;

        for( i = 0 ; i < len ; i++ )
        {
            if( pre )
            {
                exp += ',' ;
                pre = null ;
            }

            cur = days[i] ;

            if( this.days.indexOf( cur ) > -1 )
            {
                pos  = this.days.indexOf( cur ) ;
                exp += cur ;

                if( days[i+1] )
                {
                    if( this.days.indexOf(days[i+1]) === (pos+1) )
                    {
                        do
                        {
                            cur = days[i+1] ;
                            i++ ;
                            pos++ ;
                        }
                        while ( this.days.indexOf(days[i+1]) === (pos+1) );

                        exp += '-' + cur ;
                    }
                }
            }
            else if( this.specials.indexOf( cur ) > -1 )
            {
                pos = this.specials.indexOf( cur ) ;
                exp += cur ;
            }

            pre = cur ;

        }

        if( humanReadble === true )
        {
            let items ;

            switch( exp )
            {
                case '' :
                {
                    return this.strings.none ;
                }
                case 'Mo-Fr' :
                {
                    return this.strings.week ;
                }
                case 'Sa-Su' :
                {
                    return this.strings.weekend ;
                }
                case 'Mo-Su' :
                {
                    return this.strings.all ;
                }
                case 'Ph,Sh' :
                {
                    items = this.strings.days.filter(function( value , index , array )
                    {
                        return value && (value.id === 'Ph' || value.id === 'Sh') ;
                    }) ;
                    return fastformat
                    (
                        this.strings.specials,
                        items[0].name ,
                        items[1].name
                    );
                }
                default :
                {
                    if( this.days.indexOf(exp) > -1 )
                    {
                        items = this.strings.days.filter(function( value , index , array )
                        {
                            return value && value.id === exp ;
                        }) ;
                        return items[0].name ;
                    }

                    len = this.days.length ;
                    for( i = 0 ; i<len ; i++ )
                    {
                        cur = this.days[i] ;
                        items = this.strings.days.filter(function( value , index , array )
                        {
                            return value && value.id === cur ;
                        }) ;
                        if( items && items.length > 0 )
                        {
                            exp = exp.replace( cur , items[0].short ) ;
                        }
                    }

                    len = this.specials.length ;
                    for( i = 0 ; i<len ; i++ )
                    {
                        cur = this.specials[i] ;
                        items = this.strings.days.filter(function( value , index , array )
                        {
                            return value && value.id === cur ;
                        }) ;
                        if( items && items.length > 0 )
                        {
                            exp = exp.replace( cur , items[0].name ) ;
                        }
                    }
                }
            }
        }

        return exp ;
    }

    /**
     * Parse the string expression.
     * @param {string} expression
     * @memberof system.calendar.DayOfWeek
     * @function
     * @returns {Array} The array representation of all weeks defines in the passed-in string expression.
     */
    parse( expression )
    {
        let i,j,count,len ;
        let collector = {} ;
        let days  = [] ;
        if( expression && ( typeof(expression) === "string" || (expression instanceof String) ) && expression !== ''  )
        {
            let item ;
            let items = expression.split(',') ;

            len = items.length ;

            for( i = 0 ; i<len ; i++ )
            {
                item = items[i] ;

                switch( true )
                {
                    case this.days.indexOf( item ) > -1  :
                    case this.specials.indexOf( item ) > -1 :
                    {
                        collector[item] = true ;
                        break ;
                    }

                    case ( item.indexOf('-') > -1 ) :
                    {
                        item = item.split('-') ;
                        if( item.length === 2 )
                        {
                            let first = this.days.indexOf(item[0]) ;
                            let last  = this.days.indexOf(item[1]) ;
                            if( (first > -1) && (last > -1) && (last > first) )
                            {
                                let subdays = this.days.slice( first , last+1 ) ;
                                count = subdays.length ;
                                for( j = 0 ; j<count ; j++ )
                                {
                                    collector[subdays[j]] = true ;
                                }
                            }
                        }
                        break ;
                    }
                }
            }
        }

        len = this.days.length ;
        for( i = 0 ; i<len ; i++ )
        {
            if( collector[this.days[i]] === true )
            {
                days.push(this.days[i]) ;
            }
        }

        len = this.specials.length ;
        for( i = 0 ; i<len ; i++ )
        {
            if( collector[this.specials[i]] === true )
            {
                days.push(this.specials[i]) ;
            }
        }

        return days ;
    }
}

export default DayOfWeek ;