﻿// Decompiled with JetBrains decompiler
// Type: System.Timers.Timer
// Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 5ABD58FD-DF31-44FD-A492-63F2B47CC9AF
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.dll

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Threading;

namespace System.Timers
{
  /// <summary>
  /// Generates recurring events in an application.
  /// </summary>
  [DefaultEvent("Elapsed")]
  [DefaultProperty("Interval")]
  [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)]
  public class Timer : Component, ISupportInitialize
  {
    private double interval;
    private bool enabled;
    private bool initializing;
    private bool delayedEnable;
    private ElapsedEventHandler onIntervalElapsed;
    private bool autoReset;
    private ISynchronizeInvoke synchronizingObject;
    private bool disposed;
    private System.Threading.Timer timer;
    private TimerCallback callback;
    private object cookie;

    /// <summary>
    /// Gets or sets a value indicating whether the <see cref="T:System.Timers.Timer"/> should raise the <see cref="E:System.Timers.Timer.Elapsed"/> event each time the specified interval elapses or only after the first time it elapses.
    /// </summary>
    /// 
    /// <returns>
    /// true if the <see cref="T:System.Timers.Timer"/> should raise the <see cref="E:System.Timers.Timer.Elapsed"/> event each time the interval elapses; false if it should raise the <see cref="E:System.Timers.Timer.Elapsed"/> event only once, after the first time the interval elapses. The default is true.
    /// </returns>
    [Category("Behavior")]
    [TimersDescription("TimerAutoReset")]
    [DefaultValue(true)]
    public bool AutoReset
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this.autoReset;
      }
      set
      {
        if (this.DesignMode)
        {
          this.autoReset = value;
        }
        else
        {
          if (this.autoReset == value)
            return;
          this.autoReset = value;
          if (this.timer == null)
            return;
          this.UpdateTimer();
        }
      }
    }

    /// <summary>
    /// Gets or sets a value indicating whether the <see cref="T:System.Timers.Timer"/> should raise the <see cref="E:System.Timers.Timer.Elapsed"/> event.
    /// </summary>
    /// 
    /// <returns>
    /// true if the <see cref="T:System.Timers.Timer"/> should raise the <see cref="E:System.Timers.Timer.Elapsed"/> event; otherwise, false. The default is false.
    /// </returns>
    /// <exception cref="T:System.ObjectDisposedException">This property cannot be set because the timer has been disposed.</exception><exception cref="T:System.ArgumentException">The <see cref="P:System.Timers.Timer.Interval"/> property was set to a value greater than <see cref="F:System.Int32.MaxValue"/> before the timer was enabled. </exception>
    [DefaultValue(false)]
    [Category("Behavior")]
    [TimersDescription("TimerEnabled")]
    public bool Enabled
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this.enabled;
      }
      set
      {
        if (this.DesignMode)
        {
          this.delayedEnable = value;
          this.enabled = value;
        }
        else if (this.initializing)
        {
          this.delayedEnable = value;
        }
        else
        {
          if (this.enabled == value)
            return;
          if (!value)
          {
            if (this.timer != null)
            {
              this.cookie = (object) null;
              this.timer.Dispose();
              this.timer = (System.Threading.Timer) null;
            }
            this.enabled = value;
          }
          else
          {
            this.enabled = value;
            if (this.timer == null)
            {
              if (this.disposed)
                throw new ObjectDisposedException(this.GetType().Name);
              int dueTime = (int) Math.Ceiling(this.interval);
              this.cookie = new object();
              this.timer = new System.Threading.Timer(this.callback, this.cookie, dueTime, this.autoReset ? dueTime : -1);
            }
            else
              this.UpdateTimer();
          }
        }
      }
    }

    /// <summary>
    /// Gets or sets the interval at which to raise the <see cref="E:System.Timers.Timer.Elapsed"/> event.
    /// </summary>
    /// 
    /// <returns>
    /// The time, in milliseconds, between <see cref="E:System.Timers.Timer.Elapsed"/> events. The value must be greater than zero, and less than or equal to <see cref="F:System.Int32.MaxValue"/>. The default is 100 milliseconds.
    /// </returns>
    /// <exception cref="T:System.ArgumentException">The interval is less than or equal to zero.-or-The interval is greater than <see cref="F:System.Int32.MaxValue"/>, and the timer is currently enabled. (If the timer is not currently enabled, no exception is thrown until it becomes enabled.) </exception>
    [SettingsBindable(true)]
    [DefaultValue(100.0)]
    [Category("Behavior")]
    [TimersDescription("TimerInterval")]
    public double Interval
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this.interval;
      }
      set
      {
        if (value <= 0.0)
          throw new ArgumentException(SR.GetString("TimerInvalidInterval", (object) value, (object) 0));
        this.interval = value;
        if (this.timer == null)
          return;
        this.UpdateTimer();
      }
    }

    /// <summary>
    /// Gets or sets the site that binds the <see cref="T:System.Timers.Timer"/> to its container in design mode.
    /// </summary>
    /// 
    /// <returns>
    /// An <see cref="T:System.ComponentModel.ISite"/> interface representing the site that binds the <see cref="T:System.Timers.Timer"/> object to its container.
    /// </returns>
    public override ISite Site
    {
      get
      {
        return base.Site;
      }
      set
      {
        base.Site = value;
        if (!this.DesignMode)
          return;
        this.enabled = true;
      }
    }

    /// <summary>
    /// Gets or sets the object used to marshal event-handler calls that are issued when an interval has elapsed.
    /// </summary>
    /// 
    /// <returns>
    /// The <see cref="T:System.ComponentModel.ISynchronizeInvoke"/> representing the object used to marshal the event-handler calls that are issued when an interval has elapsed. The default is null.
    /// </returns>
    [DefaultValue(null)]
    [TimersDescription("TimerSynchronizingObject")]
    [Browsable(false)]
    public ISynchronizeInvoke SynchronizingObject
    {
      get
      {
        if (this.synchronizingObject == null && this.DesignMode)
        {
          IDesignerHost designerHost = (IDesignerHost) this.GetService(typeof (IDesignerHost));
          if (designerHost != null)
          {
            object obj = (object) designerHost.RootComponent;
            if (obj != null && obj is ISynchronizeInvoke)
              this.synchronizingObject = (ISynchronizeInvoke) obj;
          }
        }
        return this.synchronizingObject;
      }
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set
      {
        this.synchronizingObject = value;
      }
    }

    /// <summary>
    /// Occurs when the interval elapses.
    /// </summary>
    [TimersDescription("TimerIntervalElapsed")]
    [Category("Behavior")]
    public event ElapsedEventHandler Elapsed
    {
      add
      {
        this.onIntervalElapsed += value;
      }
      remove
      {
        this.onIntervalElapsed -= value;
      }
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.Timers.Timer"/> class, and sets all the properties to their initial values.
    /// </summary>
    public Timer()
    {
      this.interval = 100.0;
      this.enabled = false;
      this.autoReset = true;
      this.initializing = false;
      this.delayedEnable = false;
      this.callback = new TimerCallback(this.MyTimerCallback);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.Timers.Timer"/> class, and sets the <see cref="P:System.Timers.Timer.Interval"/> property to the specified number of milliseconds.
    /// </summary>
    /// <param name="interval">The time, in milliseconds, between events. The value must be greater than zero and less than or equal to <see cref="F:System.Int32.MaxValue"/>.</param><exception cref="T:System.ArgumentException">The value of the <paramref name="interval"/> parameter is less than or equal to zero, or greater than <see cref="F:System.Int32.MaxValue"/>. </exception>
    public Timer(double interval)
      : this()
    {
      if (interval <= 0.0)
        throw new ArgumentException(SR.GetString("InvalidParameter", (object) "interval", (object) interval));
      double num = Math.Ceiling(interval);
      if (num > (double) int.MaxValue || num <= 0.0)
        throw new ArgumentException(SR.GetString("InvalidParameter", (object) "interval", (object) interval));
      this.interval = (double) (int) num;
    }

    /// <summary>
    /// Begins the run-time initialization of a <see cref="T:System.Timers.Timer"/> that is used on a form or by another component.
    /// </summary>
    public void BeginInit()
    {
      this.Close();
      this.initializing = true;
    }

    /// <summary>
    /// Releases the resources used by the <see cref="T:System.Timers.Timer"/>.
    /// </summary>
    public void Close()
    {
      this.initializing = false;
      this.delayedEnable = false;
      this.enabled = false;
      if (this.timer == null)
        return;
      this.timer.Dispose();
      this.timer = (System.Threading.Timer) null;
    }

    /// <summary>
    /// Releases all resources used by the current <see cref="T:System.Timers.Timer"/>.
    /// </summary>
    /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources. </param>
    protected override void Dispose(bool disposing)
    {
      this.Close();
      this.disposed = true;
      base.Dispose(disposing);
    }

    /// <summary>
    /// Ends the run-time initialization of a <see cref="T:System.Timers.Timer"/> that is used on a form or by another component.
    /// </summary>
    /// <PermissionSet><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode"/></PermissionSet>
    public void EndInit()
    {
      this.initializing = false;
      this.Enabled = this.delayedEnable;
    }

    /// <summary>
    /// Starts raising the <see cref="E:System.Timers.Timer.Elapsed"/> event by setting <see cref="P:System.Timers.Timer.Enabled"/> to true.
    /// </summary>
    /// <exception cref="T:System.ArgumentOutOfRangeException">The <see cref="T:System.Timers.Timer"/> is created with an interval equal to or greater than <see cref="F:System.Int32.MaxValue"/> + 1, or set to an interval less than zero.</exception><PermissionSet><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode"/></PermissionSet>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public void Start()
    {
      this.Enabled = true;
    }

    /// <summary>
    /// Stops raising the <see cref="E:System.Timers.Timer.Elapsed"/> event by setting <see cref="P:System.Timers.Timer.Enabled"/> to false.
    /// </summary>
    /// <PermissionSet><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode"/></PermissionSet>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public void Stop()
    {
      this.Enabled = false;
    }

    [SuppressUnmanagedCodeSecurity]
    [DllImport("kernel32.dll")]
    internal static extern void GetSystemTimeAsFileTime(ref Timer.FILE_TIME lpSystemTimeAsFileTime);

    private void UpdateTimer()
    {
      int dueTime = (int) Math.Ceiling(this.interval);
      this.timer.Change(dueTime, this.autoReset ? dueTime : -1);
    }

    private void MyTimerCallback(object state)
    {
      if (state != this.cookie)
        return;
      if (!this.autoReset)
        this.enabled = false;
      Timer.FILE_TIME lpSystemTimeAsFileTime = new Timer.FILE_TIME();
      Timer.GetSystemTimeAsFileTime(ref lpSystemTimeAsFileTime);
      ElapsedEventArgs e = new ElapsedEventArgs(lpSystemTimeAsFileTime.ftTimeLow, lpSystemTimeAsFileTime.ftTimeHigh);
      try
      {
        ElapsedEventHandler elapsedEventHandler = this.onIntervalElapsed;
        if (elapsedEventHandler == null)
          return;
        if (this.SynchronizingObject != null && this.SynchronizingObject.InvokeRequired)
          this.SynchronizingObject.BeginInvoke((Delegate) elapsedEventHandler, new object[2]
          {
            (object) this,
            (object) e
          });
        else
          elapsedEventHandler((object) this, e);
      }
      catch
      {
      }
    }

    internal struct FILE_TIME
    {
      internal int ftTimeLow;
      internal int ftTimeHigh;
    }
  }
}
