context: //#define MonitorCallbacks
  //#define CollectStatistic
  /*
   * DAWN OF LIGHT - The first free open source DAoC server emulator
   * 
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version 2
   * of the License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   *
   */
  using System;
  using System.Collections;
  using System.Diagnostics;
  using System.IO;
  using System.Reflection;
  using System.Text;
  using System.Threading;
  using log4net;
  using ThreadState = System.Threading.ThreadState;
  
  namespace DOL.GS
  {
  	/// <summary>
  	/// The GameTimer class invokes OnTick() method after
  	/// certain intervals which are defined in milliseconds
  	/// </summary>
  	public abstract class GameTimer
  	{
  		/// <summary>
  		/// Defines a logger for this class.
  		/// </summary>
  		private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  
  		/// <summary>
  		/// Stores the reference to the next timer in the chain
  		/// </summary>
  		private GameTimer m_nextTimer;
  		/// <summary>
  		/// Stores the next execution tick and flags
  		/// </summary>
  		private long m_tick = TIMER_DISABLED;
  		/// <summary>
  		/// Stores the timer intervals
  		/// </summary>
  		private int m_interval;
  		/// <summary>
  		/// Stores the time where the timer was inserted
  		/// </summary>
  		private long m_targetTime = -1;
  		/// <summary>
  		/// Stores the time manager used for this timer
  		/// </summary>
  		private readonly TimeManager m_time;
  
  		/// <summary>
  		/// Flags the timer as disabled
  		/// </summary>
  		public static readonly long TIMER_DISABLED = long.MinValue;
  		/// <summary>
  		/// Flags the current tick timers as rescheduled
  		/// </summary>
  		public static readonly long TIMER_RESCHEDULED = 0x40000000;
  
  		/// <summary>
  		/// Constructs a new GameTimer
  		/// </summary>
  		/// <param name="time">The time manager for this timer</param>
  		public GameTimer(TimeManager time)
  		{
  			if (time == null)
  				throw new ArgumentNullException("time");
  			m_time = time;
  		}
  
  		/// <summary>
  		/// Gets the time left until this timer fires, in milliseconds.
  		/// </summary>
  		public int TimeUntilElapsed
  		{
  			get
  			{
  				long ins = m_targetTime;
  				if (ins < 0)
  					return -1;
  				return (int)((ulong)ins - (ulong)m_time.CurrentTime);
  			}
  		}
  
  		/// <summary>
  		/// Gets or sets the timer intervals in milliseconds
  		/// </summary>
  		public virtual int Interval
  		{
  			get { return m_interval; }
  			set
  			{
  				if (value < 0 || value > MaxInterval)
  					throw new ArgumentOutOfRangeException("value", value, "Interval value must be in 1 .. "+MaxInterval.ToString()+" range.");
  				m_interval = value;
  			}
  		}
  
  		/// <summary>
  		/// Gets the maximal allowed interval
  		/// </summary>
  		public long MaxInterval
  		{
  			get { return m_time.MaxInterval; }
  		}
  
  		/// <summary>
  		/// Checks whether this timer is disabled
  		/// </summary>
  		public bool IsAlive
  		{
  			get { return (m_tick & TIMER_DISABLED) == 0; }
  		}
  
  		/// <summary>
  		/// Returns short information about the timer
  		/// </summary>
  		/// <returns>Short info about the timer</returns>
  		public override string ToString()
  		{
  			return string.Format("{0} tick:0x{1:X8} interval:{2} manager:'{3}'", GetType().FullName, m_tick, m_interval, m_time.Name);
  		}
  
  		/// <summary>
  		/// Starts the timer with defined initial delay
  		/// </summary>
  		/// <param name="initialDelay">The initial timer delay. Must be more than 0 and less than MaxInterval</param>
  		public virtual void Start(int initialDelay)
  		{
  			m_time.InsertTimer(this, initialDelay);
  		}
  
  //		/// <summary>
  //		/// Starts the timer using current interval
  //		/// </summary>
  //		public virtual void Start()
  //		{ not clear what it does, imo
  //			m_time.InsertTimer(this, Interval);
  //		}
  
  		/// <summary>
  		/// Stops the timer
  		/// </summary>
  		public virtual void Stop()
  		{
  			m_time.RemoveTimer(this);
  		}
  
  		/// <summary>
  		/// Called on every timer tick
  		/// </summary>
  		protected abstract void OnTick();
  
  		private static long StopwatchFrequencyMilliseconds = Stopwatch.Frequency / 1000;
  		/// <summary>
  		/// Get the tick count, this is needed because Environment.TickCount resets to 0
  		/// when server has been up 48 days because it returned an int,
  		/// this is a long
  		/// </summary>
  		/// <returns></returns>
  		public static long GetTickCount()
  		{
  			return Stopwatch.GetTimestamp() / StopwatchFrequencyMilliseconds;
  		}
  
  		#region TimeManager
  
  		/// <summary>
  		/// This class manages all the GameTimers. It is started from
  		/// within the GameServer.Start() method and stopped from
  		/// within the GameServer.Stop() method. It runs an own thread
  		/// when it is started, that cylces through all GameTimers and
  		/// executes them at the right moment.
  		/// </summary>
  		public sealed class TimeManager
  		{
  			private readonly object m_lockObject = new object();
  			/// <summary>
  			/// Defines a logger for this class.
  			/// </summary>
  			private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  
  			/// <summary>
  			/// The size of cache array with 1ms granularity, in bits
  			/// Must be more than or equal to one bucket size
  			/// </summary>
  			public static readonly int CACHE_BITS = 14;
  			/// <summary>
  			/// The bucket size in bits. All timers with same high bits get into same bucket.
  			/// </summary>
  			public static readonly int BUCKET_BITS = 4;
  			/// <summary>
  			/// The table arrays size in bits.
  			/// Table size in milliseconds is (1 less than less than BUCKET_BITS + TABLE_BITS).
  			/// </summary>
  			public static readonly int TABLE_BITS = 17;
  			/// <summary>
  			/// Defines amount of bits that don't fit the fixed time table.
  			/// Two highest bits are reserved for flags.
  			/// </summary>
  			public static readonly int LONGTERM_BITS = 30 - BUCKET_BITS - TABLE_BITS;
  
  			/// <summary>
  			/// Defines the bitmask used to get timer cache bucket index
  			/// </summary>
  			public static readonly int CACHE_MASK = (1 << CACHE_BITS) - 1;
  			/// <summary>
  			/// Defines the bitmask used for a check if new bucket should be sorted
  			/// </summary>
  			public static readonly int BUCKET_MASK = (1 << BUCKET_BITS) - 1;
  			/// <summary>
  			/// Defines the bitmask used to get timer bucket index
  			/// (after shifting it by BUCKET_BITS!)
  			/// </summary>
  			public static readonly int TABLE_MASK = (1 << TABLE_BITS) - 1;
  			/// <summary>
  			/// Defines the bitmask used to check if timer should be delayed for another table loop
  			/// </summary>
  			public static readonly int LONGTERM_MASK = ((1 << LONGTERM_BITS) - 1) << BUCKET_BITS + TABLE_BITS;
  			/// <summary>
  			/// Defines the bitmask used to "overflow" the current millisecond
  			/// so that time table starts from 0 again.
  			/// </summary>
  			public static readonly int TICK_MASK = (1 << TABLE_BITS + BUCKET_BITS) - 1;
  
  
  			/// <summary>
  			/// The time thread
  			/// </summary>
  			private Thread m_timeThread;
  			/// <summary>
  			/// The time thread name
  			/// </summary>
  			private readonly string m_name;
  			/// <summary>
  			/// The timer is running while this flag is true
  			/// </summary>
  			private volatile bool m_running;
  			/// <summary>
  			/// The current virtual millisecond, overflows when it reach the time table end
  			/// </summary>
  			private int m_tick;
  			/// <summary>
  			/// The current manager time in milliseconds
  			/// </summary>
  			private long m_time;
  			/// <summary>
  			/// The cached bucket with 1ms granularity.
  			/// All intervals that fit this array don't need sorting.
  			/// </summary>
  			private readonly CacheBucket[] m_cachedBucket = new CacheBucket[1 << CACHE_BITS];
  			/// <summary>
              /// Stores all timers. Array index = (TimerTick>>BUCKET_BITS)&TABLE_MASK
  			/// </summary>
  			private readonly GameTimer[] m_buckets = new GameTimer[1 << TABLE_BITS];
  			/// <summary>
  			/// The count of active timers in the manager
  			/// </summary>
  			private int m_activeTimers;
  			/// <summary>
  			/// The count of invoked timers
  			/// </summary>
  			private long m_invokedCount;
  
  			/// <summary>
  			/// Holds the first and the last timers in the chain
  			/// </summary>
  			private struct CacheBucket
  			{
  				/// <summary>
  				/// The first timer in the chain
  				/// </summary>
  				public GameTimer FirstTimer;
  				/// <summary>
  				/// The last timer in the chain
  				/// </summary>
  				public GameTimer LastTimer;
  				/// <summary>
  				/// The empty bucket
  				/// </summary>
  				public static readonly CacheBucket EmptyBucket = new CacheBucket();
  			}
  
  			/// <summary>
  			/// Constructs a new time manager
  			/// </summary>
  			/// <param name="name">Thread name</param>
  			public TimeManager(string name)
  			{
  				if (name == null)
  					throw new ArgumentNullException("name");
  				m_name = name;
  #if MonitorCallbacks
  				FileStream stream = new FileStream("logs\\delays-" + m_name + ".log", FileMode.Append, FileAccess.Write, FileShare.Read);
  				m_delayLog = new StreamWriter(stream);
  				m_delayLog.WriteLine("\n\n\n\n\n===============================");
  
gt: 				m_delayLog.WriteLine("=== new log "+DateTime.Now.ToString());