/
com/planet_ink/coffee_mud/Abilities/Common/
com/planet_ink/coffee_mud/Abilities/Diseases/
com/planet_ink/coffee_mud/Abilities/Druid/
com/planet_ink/coffee_mud/Abilities/Fighter/
com/planet_ink/coffee_mud/Abilities/Languages/
com/planet_ink/coffee_mud/Abilities/Misc/
com/planet_ink/coffee_mud/Abilities/Prayers/
com/planet_ink/coffee_mud/Abilities/Properties/
com/planet_ink/coffee_mud/Abilities/Skills/
com/planet_ink/coffee_mud/Abilities/Songs/
com/planet_ink/coffee_mud/Abilities/Spells/
com/planet_ink/coffee_mud/Abilities/Thief/
com/planet_ink/coffee_mud/Abilities/Traps/
com/planet_ink/coffee_mud/Behaviors/
com/planet_ink/coffee_mud/CharClasses/interfaces/
com/planet_ink/coffee_mud/Commands/
com/planet_ink/coffee_mud/Commands/interfaces/
com/planet_ink/coffee_mud/Common/
com/planet_ink/coffee_mud/Common/interfaces/
com/planet_ink/coffee_mud/Exits/interfaces/
com/planet_ink/coffee_mud/Items/Armor/
com/planet_ink/coffee_mud/Items/Basic/
com/planet_ink/coffee_mud/Items/CompTech/
com/planet_ink/coffee_mud/Items/MiscMagic/
com/planet_ink/coffee_mud/Items/Weapons/
com/planet_ink/coffee_mud/Items/interfaces/
com/planet_ink/coffee_mud/Libraries/
com/planet_ink/coffee_mud/Libraries/interfaces/
com/planet_ink/coffee_mud/Locales/
com/planet_ink/coffee_mud/MOBS/
com/planet_ink/coffee_mud/Races/
com/planet_ink/coffee_mud/Races/interfaces/
com/planet_ink/coffee_mud/WebMacros/
com/planet_ink/coffee_mud/WebMacros/interfaces/
com/planet_ink/coffee_mud/core/
com/planet_ink/coffee_mud/core/collections/
com/planet_ink/coffee_mud/core/interfaces/
com/planet_ink/coffee_mud/core/intermud/
com/planet_ink/coffee_mud/core/intermud/i3/
com/planet_ink/coffee_web/server/
com/planet_ink/siplet/applet/
lib/
resources/factions/
resources/fakedb/
resources/progs/autoplayer/
resources/quests/holidays/
web/
web/admin.templates/
web/admin/grinder/
web/admin/images/
web/clan.templates/
web/pub.templates/
web/pub/images/mxp/
web/pub/sounds/
web/pub/textedit/
package com.planet_ink.coffee_mud.Libraries;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.core.collections.*;
import com.planet_ink.coffee_mud.core.exceptions.CMException;
import com.planet_ink.coffee_mud.core.exceptions.CoffeeMudException;
import com.planet_ink.coffee_mud.Abilities.interfaces.*;
import com.planet_ink.coffee_mud.Areas.interfaces.*;
import com.planet_ink.coffee_mud.Behaviors.interfaces.*;
import com.planet_ink.coffee_mud.CharClasses.interfaces.*;
import com.planet_ink.coffee_mud.Commands.interfaces.*;
import com.planet_ink.coffee_mud.Common.interfaces.*;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.*;
import com.planet_ink.coffee_mud.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;

import java.text.*;
import java.util.*;
import java.util.concurrent.*;

/*
   Copyright 2005-2016 Bo Zimmerman

   Licensed 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.
*/
public class CoffeeTime extends StdLibrary implements TimeManager
{
	@Override public String ID(){return "CoffeeTime";}
	protected TimeClock globalClock=null;

	@Override
	public String month2MM(String monthName)
	{
		for(int m=0;m<MONTHS.length;m++)
			if(monthName.equals(MONTHS[m]))
				if(m<9)
					return "0"+(m+1);
				else
					return String.valueOf(m+1);
		return "01";
	}

	@Override
	public String getMonthName(int number, boolean giveShort)
	{
		if(number<=0)
			number=1;
		else
		if(number>12)
			number=(number%12)+1;

		if(!giveShort)
			return MONTHS[number-1];
		else
			return SHORTMONTHS[number-1];
	}

	@Override
	public long string2Millis(String dateTimeStr)
	{
		final Calendar C=string2Date(dateTimeStr);
		if(C!=null)
			return C.getTimeInMillis();
		return 0;
	}

	@Override
	public Calendar string2Date(String dateTimeStr)
	{
		Calendar D=Calendar.getInstance();

		if(dateTimeStr==null)
			return D;
		if(dateTimeStr.trim().length()==0)
			return D;
		// for those stupid SQLServer date formats, clean them up!
		if((dateTimeStr.indexOf('.')==19)
		||((dateTimeStr.indexOf('-')==4)&&(dateTimeStr.indexOf(':')==13)))
		{
			//String TheOldDate=TheDate;
			int HH=CMath.s_int(dateTimeStr.substring(11,13));
			final int MM=CMath.s_int(dateTimeStr.substring(14,16));
			int AP=Calendar.AM;
			if(dateTimeStr.trim().endsWith("PM"))
				AP=Calendar.PM;
			else
			if(dateTimeStr.trim().endsWith("AM"))
				AP=Calendar.AM;
			else
			if(HH==0)
			{
				HH=12;
				AP=Calendar.AM;
			}
			else
			if(HH>12)
			{
				HH=HH-12;
				AP=Calendar.PM;
			}
			else
			if(dateTimeStr.toUpperCase().substring(10).indexOf('P')>=0)
				AP=Calendar.PM;
			else
			if(dateTimeStr.toUpperCase().substring(10).indexOf('A')>=0)
				AP=Calendar.AM;
			else
			if(HH==12) // as 12 always means 12 noon in international date/time -- 0 = 12am
				AP=Calendar.PM;

			if((AP==Calendar.PM)&&(HH==12))
				D.set(Calendar.HOUR,0);
			else
			if((AP==Calendar.AM)&&(HH==12))
				D.set(Calendar.HOUR,0);
			else
				D.set(Calendar.HOUR,HH);

			D.set(Calendar.AM_PM,AP);
			D.set(Calendar.MINUTE,MM);
			D.set(Calendar.SECOND,0);
			D.set(Calendar.MILLISECOND,0);

			final int YY=CMath.s_int(dateTimeStr.substring(0,4));
			D.set(Calendar.YEAR,YY);
			final int MN=CMath.s_int(dateTimeStr.substring(5,7));
			D.set(Calendar.MONTH,MN-1);
			final int DA=CMath.s_int(dateTimeStr.substring(8,10));
			D.set(Calendar.DATE,DA);
			D.set(Calendar.AM_PM,AP);
		}
		else
		{
			// If it has no time, give it one!
			if((dateTimeStr.indexOf(':')<0)
			&&(dateTimeStr.indexOf("AM")<0)
			&&(dateTimeStr.indexOf("PM")<0))
				dateTimeStr=dateTimeStr+" 5:00 PM";

			try
			{
				final DateFormat fmt=DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT);
				fmt.parse(dateTimeStr);
				D=fmt.getCalendar();
				D.set(Calendar.SECOND,0);
				D.set(Calendar.MILLISECOND,0);
			}
			catch(final ParseException e)
			{ }
		}
		confirmDateAMPM(dateTimeStr,D);
		return D;
	}

	@Override
	public boolean isValidDateString(String dateTimeStr)
	{
		if(dateTimeStr==null)
			return false;
		if(dateTimeStr.trim().length()==0)
			return false;
		// for those stupid SQLServer date formats, clean them up!
		if((dateTimeStr.indexOf('.')==19)
		||((dateTimeStr.indexOf('-')==4)&&(dateTimeStr.indexOf(':')==13)))
		{
			//String TheOldDate=TheDate;
			if(!CMath.isInteger(dateTimeStr.substring(11,13)))
				return false;
			if(!CMath.isInteger(dateTimeStr.substring(14,16)))
				return false;
			if(!CMath.isInteger(dateTimeStr.substring(0,4)))
				return false;
			if(!CMath.isInteger(dateTimeStr.substring(5,7)))
				return false;
			if(!CMath.isInteger(dateTimeStr.substring(8,10)))
				return false;
		}
		else
		{
			// If it has no time, give it one!
			if((dateTimeStr.indexOf(':')<0)
			&&(dateTimeStr.indexOf("AM")<0)
			&&(dateTimeStr.indexOf("PM")<0))
				dateTimeStr=dateTimeStr+" 5:00 PM";
			try
			{
				final DateFormat fmt=DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT);
				fmt.parse(dateTimeStr);
			}
			catch(final ParseException e)
			{ return false; }
		}
		return true;
	}

	private void confirmDateAMPM(String TheDate, Calendar D)
	{
		try
		{
			if(TheDate.trim().endsWith("PM"))
			{
				if(D.get(Calendar.AM_PM)==Calendar.AM)
					D.set(Calendar.AM_PM,Calendar.PM);
				if(D.get(Calendar.AM_PM)==Calendar.AM)
					D.add(Calendar.HOUR,12);
				if(D.get(Calendar.AM_PM)==Calendar.AM)
					D.setTimeInMillis(D.getTimeInMillis()+(12*60*60*1000));
			}
			else
			if(TheDate.trim().endsWith("AM"))
			{
				if(D.get(Calendar.AM_PM)==Calendar.PM)
					D.set(Calendar.AM_PM,Calendar.AM);
				if(D.get(Calendar.AM_PM)==Calendar.PM)
					D.add(Calendar.HOUR,-12);
				if(D.get(Calendar.AM_PM)==Calendar.PM)
					D.setTimeInMillis(D.getTimeInMillis()-(12*60*60*1000));
			}
		}
		catch(final Exception e)
		{ }
	}

	@Override
	public String convertHour(String hours24)
	{
		int IntHour =  CMath.s_int(hours24);
		if (IntHour > 12)
		{
			IntHour = IntHour-12;
		}
		else
			if (IntHour == 0)
				IntHour = 12;

		hours24 = Integer.toString(IntHour);
		return hours24;
	}

	@Override
	public String getAMPM(String TheHour)
	{
		String Stamp;

		final int IntHour =  CMath.s_int(TheHour);
		if (IntHour >= 12)
			Stamp = "PM";
		else
			Stamp = "AM";
		return Stamp;
	}

	@Override
	public String getTheIntZoneID(int theRawOffset)
	{
		if (theRawOffset == 0)  		// GMT 0
			return "GMT";
		if (theRawOffset == 3600000)	// GMT 1
			return "CET";
		if (theRawOffset == 7200000)	// GMT 2
			return "CAT";
		if (theRawOffset == 10800000)   // GMT 3
			return "EAT";
		if (theRawOffset == 12600000)   // GMT 3.5
			return "MET";
		if (theRawOffset == 14400000)   // GMT 4
			return "NET";
		if (theRawOffset == 18000000)   // GMT 5
			return "PLT";
		if (theRawOffset == 19800000)   // GMT 5.5
			return "IST";
		if (theRawOffset == 21600000)   // GMT 6
			return "BST";
		if (theRawOffset == 25200000)   // GMT 7
			return "VST";
		if (theRawOffset == 28800000)   // GMT 8
			return "CTT";
		if (theRawOffset == 32400000)   // GMT 9
			return "JST";
		if (theRawOffset == 34200000)   // GMT 9.5
			return "ACT";
		if (theRawOffset == 36000000)   // GMT 10
			return "AET";
		if (theRawOffset == 39600000)   // GMT 11
			return "SST";
		if (theRawOffset == 43200000)   // GMT 12
			return "NST";
		if (theRawOffset == -39600000)  // GMT -11
			return "MIT";
		if (theRawOffset == -36000000)  // GMT -10
			return "HST";
		if (theRawOffset == -32400000)  // GMT -9
			return "AST";
		if (theRawOffset == -28800000)  // GMT -8
			return "PST";
		if (theRawOffset == -25200000)  // GMT -7
			return "MST";
		if (theRawOffset == -21600000)  // GMT -6
			return "CST";
		if (theRawOffset == -18000000)  // GMT -5
			return "EST";
		if (theRawOffset == -14400000)  // GMT -4
			return "ADT";
		if (theRawOffset == -12600000)  // GMT -3.5
			return "CNT";
		if (theRawOffset == -10800000)  // GMT -3
			return "AGT";
		if (theRawOffset == -7200000)   // GMT -2
			return "BET";
		if (theRawOffset == -3600000)   // GMT -1
			return "EET";

		return "GMT";

	}

	@Override
	public String getTheTimeZone(String theID)
	{
		if (theID.equalsIgnoreCase("CET"))
			return "Europe/Paris";
		if (theID.equalsIgnoreCase("ADT"))
			return "America/Halifax";
		if (theID.equalsIgnoreCase("BET"))
			return "Atlantic/South_Georgia";
		if (theID.equalsIgnoreCase("EET"))
			return "Atlantic/Azores";
		if (theID.equalsIgnoreCase("CAT"))
			return "Europe/Athens";
		if (theID.equalsIgnoreCase("EAT"))
			return "Asia/Riyadh";

		return theID;
	}

	@Override
	public String date2MonthString(long time, boolean shortName)
	{
		final Calendar C=makeCalendar(time);
		return getMonthName(C.get(Calendar.MONTH)+1,shortName);
	}

	@Override
	public String date2MonthDateString(long time, boolean shortName)
	{
		final Calendar C=makeCalendar(time);
		return getMonthName(C.get(Calendar.MONTH)+1,shortName) + " " + C.get(Calendar.DAY_OF_MONTH);
	}

	@Override
	public String date2DayOfMonthString(long time)
	{
		final Calendar C=makeCalendar(time);
		String Day=Integer.toString(C.get(Calendar.DAY_OF_MONTH)).trim();
		if (Day.length()==1)
			Day = "0" + Day;
		return Day;
	}

	@Override
	public String twoDigits(long num)
	{
	   final String s=Long.toString(num);
	   if(s.length()==1)
	   	return "0"+s;
	   return s;
	}

	@Override
	public String date2YYYYString(long time)
	{
		final Calendar C=makeCalendar(time);
		String Year=Integer.toString(C.get(Calendar.YEAR)).trim();
		if (Year.length()==2)
			Year = "20" + Year;
		return Year;
	}

	@Override
	public String date2HRString(long time)
	{
		return date2HRString(makeCalendar(time));
	}


	@Override
	public String date2MINString(long time)
	{
		return date2MINString(makeCalendar(time));
	}

	public String date2HRString(Calendar C)
	{
		int IntHour = C.get(Calendar.HOUR);
		if (IntHour==0)
			IntHour=12;

		String StrHour=Integer.toString(IntHour);
		if (StrHour.length()==1)
			StrHour = "0" + StrHour;
		return StrHour;
	}

	public String date2MINString(Calendar C)
	{
		int IntMin = C.get(Calendar.MINUTE);
		final int remainder = IntMin % 5;
		if (remainder != 0)
		{
			if (remainder >= 3)
			{
				IntMin = IntMin + (5 - remainder);
				if (IntMin == 60)
					IntMin = 55;
			}
			else
				IntMin = IntMin - remainder;
		}
		String StrMin=Integer.toString(IntMin);
		if (StrMin.length()==1)
			StrMin = "0" + StrMin;
		return StrMin;
	}

	@Override
	public String date2ZoneString(long time)
	{
		final Calendar C=makeCalendar(time);
		TimeZone CurrentZone;
		CurrentZone = C.getTimeZone();
		String theID = CurrentZone.getID();
		theID = getTheIntZoneID(CurrentZone.getRawOffset());

		return  theID;
	}

	@Override
	public String date2AMPMString(long time)
	{
		return date2AMPMString(makeCalendar(time));
	}

	public String date2AMPMString(Calendar C)
	{
		if (C.get(Calendar.AM_PM)==Calendar.PM)
			return "PM";
		else
			return "AM";
	}

	@Override
	public String date2APTimeString(long time)
	{
		final Calendar C=makeCalendar(time);
		return date2HRString(C)+":"+date2MINString(C)+" "+date2AMPMString(C);
	}

	@Override
	public String date2BriefString(long time)
	{
		final Calendar C=makeCalendar(time);
		final Calendar nowC=Calendar.getInstance();
		final StringBuilder str=new StringBuilder();
		if((nowC.get(Calendar.YEAR)!=C.get(Calendar.YEAR))
		||(nowC.get(Calendar.MONTH)!=C.get(Calendar.MONTH))
		||(nowC.get(Calendar.DATE)!=C.get(Calendar.DATE)))
			str.append(C.get(Calendar.YEAR)).append("/").append(C.get(Calendar.MONTH)+1).append("/").append(C.get(Calendar.DATE)).append(" ");
		str.append(date2HRString(C)).append(":").append(date2MINString(C)).append(date2AMPMString(C).toLowerCase());
		return str.toString();
	}

	private Calendar makeCalendar(long time)
	{
		final Calendar C=Calendar.getInstance();
		C.setTimeInMillis(time);
		return C;
	}
	@Override
	public String date2String(Calendar C)
	{
		String MINUTE=Integer.toString(C.get(Calendar.MINUTE)).trim();
		if(MINUTE.length()==1)
			MINUTE="0"+MINUTE;
		String AMPM="AM";
		if(C.get(Calendar.AM_PM)==Calendar.PM)
			AMPM="PM";
		int Hour=C.get(Calendar.HOUR);
		if(Hour==0)
			Hour=12;
		String Year=Integer.toString(C.get(Calendar.YEAR));
		if(Year.length()<4)
		{
			if(Year.length()<2)
				Year=("0"+Year);
			if(Year.length()<2)
				Year=("0"+Year);
			final int Yr=CMath.s_int(Year);
			if(Yr<50)
				Year="20"+Year;
			else Year="19"+Year;
		}
		return (C.get(Calendar.MONTH)+1)+"/"+C.get(Calendar.DATE)+"/"+Year+" "+Hour+":"+MINUTE+" "+AMPM;
	}

	@Override
	public String date2String(long time)
	{
		final Calendar C=makeCalendar(time);
		return date2String(C);
	}

	@Override
	public String date2EllapsedTime(long time, TimeUnit minUnit, boolean shortest)
	{
		final StringBuilder str=new StringBuilder("");
		if(time > (TimeManager.MILI_YEAR))
		{
			final int num=(int)Math.round(CMath.floor(CMath.div(time,TimeManager.MILI_YEAR)));
			time = time - (num *TimeManager.MILI_YEAR);
			str.append(num+(shortest?"y":(" year"+(num!=1?"s":""))));
		}
		if(time > (TimeManager.MILI_MONTH))
		{
			if(str.length()>0)
				str.append(shortest?" ":", ");
			final int num=(int)Math.round(CMath.floor(CMath.div(time,TimeManager.MILI_MONTH)));
			time = time - (num *TimeManager.MILI_MONTH);
			str.append(num+(shortest?"M":(" month"+(num!=1?"s":""))));
		}
		if(time > (TimeManager.MILI_WEEK))
		{
			if(str.length()>0)
				str.append(shortest?" ":", ");
			final int num=(int)Math.round(CMath.floor(CMath.div(time,TimeManager.MILI_WEEK)));
			time = time - (num *TimeManager.MILI_WEEK);
			str.append(num+(shortest?"w":(" week"+(num!=1?"s":""))));
		}
		if(time > (TimeManager.MILI_DAY))
		{
			if(str.length()>0)
				str.append(shortest?" ":", ");
			final int num=(int)Math.round(CMath.floor(CMath.div(time,TimeManager.MILI_DAY)));
			time = time - (num *TimeManager.MILI_DAY);
			str.append(num+(shortest?"d":(" day"+(num!=1?"s":""))));
		}
		if(minUnit == TimeUnit.DAYS)
			return str.toString().trim();
		if(time > (TimeManager.MILI_HOUR))
		{
			if(str.length()>0)
				str.append(shortest?" ":", ");
			final int num=(int)Math.round(CMath.floor(CMath.div(time,TimeManager.MILI_HOUR)));
			time = time - (num *TimeManager.MILI_HOUR);
			str.append(num+(shortest?"h":(" hour"+(num!=1?"s":""))));
		}
		if(minUnit == TimeUnit.HOURS)
			return str.toString().trim();
		if(time > (TimeManager.MILI_MINUTE))
		{
			if(str.length()>0)
				str.append(shortest?" ":", ");
			final int num=(int)Math.round(CMath.floor(CMath.div(time,TimeManager.MILI_MINUTE)));
			time = time - (num *TimeManager.MILI_MINUTE);
			str.append(num+(shortest?"m":(" minute"+(num!=1?"s":""))));
		}
		if(minUnit == TimeUnit.MINUTES)
			return str.toString().trim();
		if(time > (TimeManager.MILI_SECOND))
		{
			if(str.length()>0)
				str.append(shortest?" ":", ");
			final int num=(int)Math.round(CMath.floor(CMath.div(time,TimeManager.MILI_SECOND)));
			time = time - (num*TimeManager.MILI_SECOND);
			str.append(num+(shortest?"s":(" second"+(num!=1?"s":""))));
		}
		if(minUnit == TimeUnit.SECONDS)
			return str.toString().trim();
		if(str.length()>0)
			str.append(shortest?" ":", ");
		return str.append(time+(shortest?"ms":(" millisecond"+(time!=1?"s":"")))).toString().trim();
	}

	@Override
	public String date2BestShortEllapsedTime(long t)
	{
		t=t/1000;
		if(t>60)
		{
			t=t/60;
			if(t>120)
			{
				t=t/60;
				if(t>48)
				{
					t=t/24;
					return t+"d";
				}
				else
					return t+"h";
			}
			else
				return t+"m";
		}
		else
			return t+"s";
	}
	
	@Override
	public String date2SmartEllapsedTime(long time, boolean shortest)
	{
		if(time > TimeManager.MILI_DAY*2)
			return date2EllapsedTime(time,TimeUnit.DAYS,shortest);
		if(time > TimeManager.MILI_HOUR*2)
			return date2EllapsedTime(time,TimeUnit.HOURS,shortest);
		if(time > TimeManager.MILI_MINUTE*2)
			return date2EllapsedTime(time,TimeUnit.MINUTES,shortest);
		if(time > TimeManager.MILI_SECOND*2)
			return date2EllapsedTime(time,TimeUnit.SECONDS,shortest);
		return date2EllapsedTime(time,null,shortest);
	}

	@Override
	public String date2SecondsString(long time)
	{
		final Calendar C=makeCalendar(time);
		final String StrDate=date2String(C);
		if(StrDate.length()<3)
			return StrDate;
		return (StrDate.substring(0,StrDate.length()-3)+":"+C.get(Calendar.SECOND)+" "+StrDate.substring(StrDate.length()-2));
	}

	@Override
	public String date2DateString(long time)
	{
		String T=date2String(time);
		if(T.indexOf(' ')>0)
			T=T.substring(0,T.indexOf(' '));
		return T.trim();
	}

	@Override
	public String date2Date2String(long time)
	{
		String T=date2DateString(time);
		final int x=T.lastIndexOf('/');
		T=T.substring(0,x+1)+T.substring(x+3);
		return T.trim();
	}

	@Override
	public String smtpDateFormat(long time)
	{
		final Calendar senddate=makeCalendar(time);
		String formatted = "hold";

		final String Day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
		final String Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul","Aug", "Sep", "Oct", "Nov", "Dec"};
		final int dow=senddate.get(Calendar.DAY_OF_WEEK)-1;
		final int date=senddate.get(Calendar.DAY_OF_MONTH);
		final int m=senddate.get(Calendar.MONTH);
		final int y=senddate.get(Calendar.YEAR);
		final int h=senddate.get(Calendar.HOUR_OF_DAY);
		final int min=senddate.get(Calendar.MINUTE);
		final int s=senddate.get(Calendar.SECOND);
		int zof=senddate.get(Calendar.ZONE_OFFSET);
		int dof=senddate.get(Calendar.DST_OFFSET);

		formatted = Day[dow] + ", ";
		formatted = formatted + String.valueOf(date) + " ";
		formatted = formatted + Month[m] + " ";
		formatted = formatted + String.valueOf(y) + " ";
		if (h < 10) formatted = formatted + "0";
		formatted = formatted + String.valueOf(h) + ":";
		if (min < 10) formatted = formatted + "0";
		formatted = formatted + String.valueOf(min) + ":";
		if (s < 10) formatted = formatted + "0";
		formatted = formatted + String.valueOf(s) + " ";
		if ((zof + dof) < 0)
			formatted = formatted + "-";
		else
			formatted = formatted + "+";

		zof=zof/1000; // now in seconds
		zof=zof/60; // now in minutes

		dof=dof/1000; // now in seconds
		dof=dof/60; // now in minutes

		if ((Math.abs(zof + dof)/60) < 10) formatted = formatted + "0";
		formatted = formatted + String.valueOf(Math.abs(zof + dof)/60);
		if ((Math.abs(zof + dof)%60) < 10) formatted = formatted + "0";
		formatted = formatted + String.valueOf(Math.abs(zof + dof)%60);

		return formatted;
	}

	@Override
	public TimeClock globalClock()
	{
		if(globalClock==null)
		{
			globalClock=(TimeClock)CMClass.getCommon("DefaultTimeClock");
			if(globalClock!=null)
				globalClock.setLoadName("GLOBAL");
		}
		return globalClock;
	}

	private double getTickExpressionMultiPlier(String lastWord)
	{
		lastWord=lastWord.toUpperCase().trim();
		if(lastWord.startsWith("MINUTE")||lastWord.equals("MINS")||lastWord.equals("MIN"))
			return CMath.div(TimeManager.MILI_MINUTE,CMProps.getTickMillisD());
		else
		if(lastWord.startsWith("SECOND")||lastWord.equals("SECS")||lastWord.equals("SEC"))
			return CMath.div(TimeManager.MILI_SECOND,CMProps.getTickMillisD());
		else
		if(lastWord.startsWith("HOUR"))
			return CMath.div(TimeManager.MILI_HOUR,CMProps.getTickMillisD());
		else
		if(lastWord.startsWith("DAY")||lastWord.equals("DAYS"))
			return CMath.div(TimeManager.MILI_DAY,CMProps.getTickMillisD());
		else
		if(lastWord.startsWith("TICK"))
			return 1.0;
		else
		if(lastWord.startsWith("MUDHOUR"))
			return CMath.div(CMProps.getMillisPerMudHour(),CMProps.getTickMillisD());
		else
		if(lastWord.startsWith("MUDDAY"))
			return CMath.div(CMProps.getMillisPerMudHour()
					*globalClock().getHoursInDay()
					,CMProps.getTickMillisD());
		else
		if(lastWord.startsWith("MUDWEEK"))
			return CMath.div(CMProps.getMillisPerMudHour()
					*globalClock().getHoursInDay()
					*globalClock().getDaysInWeek()
					,CMProps.getTickMillisD());
		else
		if(lastWord.startsWith("MUDMONTH"))
			return CMath.div(CMProps.getMillisPerMudHour()
					*globalClock().getHoursInDay()
					*globalClock().getDaysInMonth()
					,CMProps.getTickMillisD());
		else
		if(lastWord.startsWith("MUDYEAR"))
			return CMath.div(CMProps.getMillisPerMudHour()
					*globalClock().getHoursInDay()
					*globalClock().getDaysInMonth()
					*globalClock().getMonthsInYear()
					,CMProps.getTickMillisD());
		return 0.0;
	}

	@Override
	public boolean isTickExpression(String val)
	{
		val=val.trim();
		if(CMath.isMathExpression(val))
			return true;
		final int x=val.lastIndexOf(' ');
		if(x<0)
			return CMath.isMathExpression(val);
		final double multiPlier=getTickExpressionMultiPlier(val.substring(x+1));
		if(multiPlier==0.0)
			return CMath.isMathExpression(val);
		return CMath.isMathExpression(val.substring(0,x).trim());
	}


	@Override
	public int parseTickExpression(String val)
	{
		val=val.trim();
		if(CMath.isMathExpression(val))
			return CMath.s_parseIntExpression(val);
		final int x=val.lastIndexOf(' ');
		if(x<0)
			return CMath.s_parseIntExpression(val);
		final double multiPlier=getTickExpressionMultiPlier(val.substring(x+1));
		if(multiPlier==0.0)
			return CMath.s_parseIntExpression(val);
		return (int)Math.round(CMath.mul(multiPlier,CMath.s_parseIntExpression(val.substring(0,x).trim())));
	}

	@Override
	public TimeClock localClock(Physical P)
	{
		if(P instanceof Area)
			return ((Area)P).getTimeObj();
		if(P instanceof Room)
			return localClock(((Room)P).getArea());
		if(P instanceof Item)
			return localClock(((Item)P).owner());
		if(P instanceof MOB)
			return localClock(((MOB)P).location());
		return globalClock();
	}
}