////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package mx.formatters
{

// import flash.events.Event;
import org.apache.royale.events.Event;

import mx.core.mx_internal;
import mx.resources.IResourceManager;
import mx.resources.ResourceManager;

use namespace mx_internal;

// [ResourceBundle("formatters")]
// [ResourceBundle("SharedResources")]

/**
 *  The DateBase class contains the localized string information
 *  used by the mx.formatters.DateFormatter class and the parsing function
 *  that renders the pattern.
 *  This is a helper class for the DateFormatter class that is not usually
 *  used independently.
 *
 *  @see mx.formatters.DateFormatter
 *  
 *  @langversion 3.0
 *  @playerversion Flash 9
 *  @playerversion AIR 1.1
 *  @productversion Flex 3
 */
public class DateBase
{
    // include "../core/Version.as";

    //--------------------------------------------------------------------------
    //
    //  Class variables
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     */
    private static var initialized:Boolean = false;

    /**
     *  @private
     *  Storage for the resourceManager getter.
     *  This gets initialized on first access,
     *  not at static initialization time, in order to ensure
     *  that the Singleton registry has already been initialized.
     */
    private static var _resourceManager:IResourceManager;
    
    /**
     *  @private
     *  A reference to the object which manages
     *  all of the application's localized resources.
     *  This is a singleton instance which implements
     *  the IResourceManager interface.
     */
    private static function get resourceManager():IResourceManager
    {
        if (!_resourceManager)
            _resourceManager = ResourceManager.getInstance();

        return _resourceManager;
    }
    
    //--------------------------------------------------------------------------
    //
    //  Class properties
    //
    //--------------------------------------------------------------------------
        
    //----------------------------------
    //  dayNamesLong
    //----------------------------------

    /**
     *  @private
     *  Storage for the dayNamesLong property.
     */
    private static var _dayNamesLong:Array; /* of String */
    
    /**
     *  @private
     */
    private static var dayNamesLongOverride:Array /* of String */ = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

    /**
     *  Long format of day names.
     * 
     *  @default ["Sunday", "Monday", "Tuesday", "Wednesday",
     *  "Thursday", "Friday", "Saturday"]
     *  
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public static function get dayNamesLong():Array /* of String */
    {
        initialize();

        return _dayNamesLong;
    }

    /**
     *  @private
     */
    public static function set dayNamesLong(value:Array /* of String*/):void
    {
        dayNamesLongOverride = value;

        _dayNamesLong = value != null ?
                        value :
                        resourceManager.getStringArray(
                            "SharedResources", "dayNames");
    }
        
    //----------------------------------
    //  dayNamesShort
    //----------------------------------

    /**
     *  @private
     *  Storage for the dayNamesShort property.
     */
    private static var _dayNamesShort:Array = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; /* of String */
    
    /**
     *  @private
     */
    private static var dayNamesShortOverride:Array = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; /* of String */

    /**
     *  Short format of day names.
     * 
     *  @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
     *  
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public static function get dayNamesShort():Array /* of String */
    {
        initialize();

        return _dayNamesShort;
    }

    /**
     *  @private
     */
    public static function set dayNamesShort(value:Array /* of String*/):void
    {
        dayNamesShortOverride = value;

        _dayNamesShort = value != null ?
                         value :
                         resourceManager.getStringArray(
                             "formatters", "dayNamesShort");
    }
    
    //----------------------------------
    //  defaultStringKey
    //----------------------------------

    /**
     *  @private
     */     
    mx_internal static function get defaultStringKey():Array /* of String */
    {
        initialize();

        return monthNamesLong.concat(timeOfDay);
    }
    
    //----------------------------------
    //  monthNamesLong
    //----------------------------------

    /**
     *  @private
     *  Storage for the monthNamesLong property.
     */
    private static var _monthNamesLong:Array; /* of String */
    
    /**
     *  @private
     */
    private static var monthNamesLongOverride:Array /* of String */ = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

    /**
     *  Long format of month names.
     *
     *  @default ["January", "February", "March", "April", "May", "June", 
     *  "July", "August", "September", "October", "November", "December"].
     *  
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public static function get monthNamesLong():Array /* of String */
    {
        initialize();

        return _monthNamesLong;
    }

    /**
     *  @private
     */
    public static function set monthNamesLong(value:Array /* of String*/):void
    {
        monthNamesLongOverride = value;

        _monthNamesLong = value != null ?
                          value :
                          resourceManager.getStringArray(
                              "SharedResources", "monthNames");

        if (value == null)
        {
            // Currently there is no way to get a null 
            // string from resourceBundles using getString
            // Hence monthSymbol is a space in English, but
            // we actually want it to be a null string.
            var monthSymbol:String = resourceManager.getString(
                "SharedResources", "monthSymbol");
            if (monthSymbol != " ")
            {
                // _monthNamesLong will be null if there are no resources.
                var n:int = _monthNamesLong ? _monthNamesLong.length : 0;
                for (var i:int = 0; i < n; i++)
                {
                    _monthNamesLong[i] += monthSymbol;
                }
            }
        }
    }
                
    //----------------------------------
    //  monthNamesShort
    //----------------------------------

    /**
     *  @private
     *  Storage for the monthNamesShort property.
     */
    private static var _monthNamesShort:Array = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct","Nov", "Dec"]; /* of String */
    
    /**
     *  @private
     */
    private static var monthNamesShortOverride:Array = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct","Nov", "Dec"]; /* of String */

    /**
     *  Short format of month names.
     *
     *  @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
     *  "Jul", "Aug", "Sep", "Oct","Nov", "Dec"]
     *  
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public static function get monthNamesShort():Array /* of String */
    {
        initialize();

        return _monthNamesShort;
    }

    /**
     *  @private
     */
    public static function set monthNamesShort(value:Array /* of String*/):void
    {
        monthNamesShortOverride = value;

        _monthNamesShort = value != null ?
                           value :
                           resourceManager.getStringArray(
                               "formatters", "monthNamesShort");
        if (value == null)
        {
            // Currently there is no way to get a null 
            // string from resourceBundles using getString
            // Hence monthSymbol is a space in English, but
            // we actually want it to be a null string.
            var monthSymbol:String = resourceManager.getString(
                "SharedResources", "monthSymbol");
            if (monthSymbol != " ")
            {
                // _monthNamesShort will be null if there are no resources.
                var n:int = _monthNamesShort ? _monthNamesShort.length : 0;
                for (var i:int = 0; i < n; i++)
                {
                    _monthNamesShort[i] += monthSymbol;
                }
            }
        }
    }
            
    //----------------------------------
    //  timeOfDay
    //----------------------------------

    /**
     *  @private
     *  Storage for the timeOfDay property.
     */
    private static var _timeOfDay:Array; /* of String */
    
    /**
     *  @private
     */
    private static var timeOfDayOverride:Array = /* of String */["AM", "PM"];

    /**
     *  Time of day names.
     * 
     *  @default ["AM", "PM"]
     *  
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public static function get timeOfDay():Array /* of String */ 
    {
        initialize();

        return _timeOfDay;
    }

    /**
     *  @private
     */
    public static function set timeOfDay(value:Array /* of String */):void
    {
        timeOfDayOverride = value;

        var am:String = resourceManager.getString("formatters", "am");
        var pm:String = resourceManager.getString("formatters", "pm");

        _timeOfDay = value != null ? value : [ am, pm ];
    }

	/**
	 *  @private
	 */
	private static var _timezoneName:String = "GMT";
	
	/**
	 *  Timezone name.
	 * 
	 *  @default "GMT"
	 *  
	 *  @langversion 3.0
	 *  @playerversion Flash 9
	 *  @playerversion AIR 1.1
	 *  @productversion  Apache Flex 4.10
	 */
	public static function get timezoneName():String
	{
		return _timezoneName;
	}
	
	/**
	 *  @private
	 */
	public static function set timezoneName(value:String):void
	{
		_timezoneName = value;
	}
	
	/**
	 *  @private
	 */
	private static var _timezoneHourMinuteSeperator:String = ":";
	
	/**
	 *  Timezone hour/minute seperator.
	 * 
	 *  @default ":"
	 *  
	 *  @langversion 3.0
	 *  @playerversion Flash 9
	 *  @playerversion AIR 1.1
	 *  @productversion Apache Flex 4.10
	 */
	public static function get timezoneHourMinuteSeperator():String
	{
		return _timezoneHourMinuteSeperator;
	}
	
	/**
	 *  @private
	 */
	public static function set timezoneHourMinuteSeperator(value:String):void
	{
		_timezoneHourMinuteSeperator = value;
	}
	

    //--------------------------------------------------------------------------
    //
    //  Class methods
    //
    //--------------------------------------------------------------------------

    /**
     *  @private    
     */
    private static function initialize():void
    {
        if (!initialized)
        {
            // Register as a weak listener for "change" events
            // from ResourceManager.
            /*resourceManager.addEventListener(
                Event.CHANGE, static_resourceManager_changeHandler,
                false, 0, true);*/

            static_resourcesChanged();

            initialized = true;
        }
    }

    /**
     *  @private    
     */
    private static function static_resourcesChanged():void
    {
        dayNamesLong = dayNamesLongOverride;
        dayNamesShort = dayNamesShortOverride;
        monthNamesLong = monthNamesLongOverride;
        monthNamesShort = monthNamesShortOverride;
        timeOfDay = timeOfDayOverride;
    }

    /**
     *  @private
     *  Parses token objects and renders the elements of the formatted String.
     *  For details about token objects, see StringFormatter.
     *
     *  @param date Date object.
     *
     *  @param tokenInfo Array object that contains token object descriptions.
     *
     *  @return Formatted string.
     */
    mx_internal static function extractTokenDate(date:Date,
                                            tokenInfo:Object):String
    {
        initialize();

        var result:String = "";
        
        var key:int = int(tokenInfo.end) - int(tokenInfo.begin);
        
        var day:int;
        var hours:int;
        
        switch (tokenInfo.token)
        {
            case "Y":
            {
                // year
                var year:String = date.getFullYear().toString();
                if (key < 3)
                    return year.substr(2);
                else if (key > 4)
                    return setValue(Number(year), key);
                else
                    return year;
            }

            case "M":
            {
                // month in year
                var month:int = int(date.getMonth());
                if (key < 3)
                {
                    month++; // zero based
                    result += setValue(month, key);
                    return result;
                }
                else if (key == 3)
                {
                    return monthNamesShort[month];
                }
                else
                {
                    return monthNamesLong[month];
                }
            }

            case "D":
            {
                // day in month
                day = int(date.getDate());
                result += setValue(day, key);
                return result;
            }

            case "E":
            {
                // day in the week
                day = int(date.getDay());
                if (key < 3)
                {
                    result += setValue(day, key);
                    return result;
                }
                else if (key == 3)
                {
                    return dayNamesShort[day];
                }
                else
                {
                    return dayNamesLong[day];
                }
            }

            case "A":
            {
                // am/pm marker
                hours = int(date.getHours());
                if (hours < 12)
                    return timeOfDay[0];
                else
                    return timeOfDay[1];
            }

            case "H":
            {
                // hour in day (1-24)
                hours = int(date.getHours());
                if (hours == 0)
                    hours = 24;
                result += setValue(hours, key);
                return result;
            }

            case "J":
            {
                // hour in day (0-23)
                hours = int(date.getHours());
                result += setValue(hours, key);
                return result;
            }

            case "K":
            {
                // hour in am/pm (0-11)
                hours = int(date.getHours());
                if (hours >= 12)
                    hours = hours - 12;
                result += setValue(hours, key);
                return result;
            }

            case "L":
            {
                // hour in am/pm (1-12)
                hours = int(date.getHours());
                if (hours == 0)
                    hours = 12;
                else if (hours > 12)
                    hours = hours - 12;
                result += setValue(hours, key);
                return result;
            }

            case "N":
            {
                // minutes in hour
                var mins:int = int(date.getMinutes());
                result += setValue(mins, key);
                return result;
            }

            case "S":
            {
                // seconds in minute
                var sec:int = int(date.getSeconds());
                result += setValue(sec, key);
                return result;
            }
            
			case "Q":
			{
				// milliseconds in second
				var ms:int = int(date.getMilliseconds());
				result += setValue(ms, key);
				return result;
			}
				
			case "Z":
			{
				// timezone offset
				result += timezoneName;
				return result;
			}
				
			case "O":
			{
				// timezone offset
				var offset:int = -1 * int(date.timezoneOffset);
				hours = offset/60;
				mins = offset - hours*60;
				var tzStr:String = "";
				
				if (key <= 2 && mins == 0)
					tzStr += setValue(hours, key);
				else
					tzStr += setValue(hours, key-2)
						+ timezoneHourMinuteSeperator 
						+ setValue(mins, 2);
					
				if (offset >= 0)
					tzStr = "+" + tzStr;
				
				result += tzStr;
				
				return result;
			}
        }

        return result;
    }

    /**
     *  @private
     *  Makes a given length of digits longer by padding with zeroes.
     *
     *  @param value Value to pad.
     *
     *  @param key Length of the string to pad.
     *
     *  @return Formatted string.
     */
    private static function setValue(value:Object, key:int):String
    {
        var result:String = "";

        var vLen:int = value.toString().length;
        if (vLen < key)
        {
            var n:int = key - vLen;
            for (var i:int = 0; i < n; i++)
            {
                result += "0"
            }
        }

        result += value.toString();

        return result;
    }

    //--------------------------------------------------------------------------
    //
    //  Class event handlers
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     */
    private static function static_resourceManager_changeHandler(event:Event):void
    {
        static_resourcesChanged();
    }
}

}
