context: using System;
  using System.Collections.Generic;
  using System.Net;
  using Server.Mobiles;
  
  namespace Server.Factions
  {
      public enum ElectionState
      {
          Pending,
          Campaign,
          Election
      }
  
      public class Election
      {
          public static readonly TimeSpan PendingPeriod = TimeSpan.FromDays(5.0);
          public static readonly TimeSpan CampaignPeriod = TimeSpan.FromDays(1.0);
          public static readonly TimeSpan VotingPeriod = TimeSpan.FromDays(3.0);
          public const int MaxCandidates = 10;
          public const int CandidateRank = 5;
          private readonly Faction m_Faction;
          private readonly List<Candidate> m_Candidates;
          private ElectionState m_State;
          private DateTime m_LastStateTime;
          private Timer m_Timer;
          public Election(Faction faction)
          {
              this.m_Faction = faction;
              this.m_Candidates = new List<Candidate>();
  
              this.StartTimer();
          }
  
          public Election(GenericReader reader)
          {
              int version = reader.ReadEncodedInt();
  
              switch ( version )
              {
                  case 0:
                      {
                          this.m_Faction = Faction.ReadReference(reader);
  
                          this.m_LastStateTime = reader.ReadDateTime();
                          this.m_State = (ElectionState)reader.ReadEncodedInt();
  
                          this.m_Candidates = new List<Candidate>();
  
                          int count = reader.ReadEncodedInt();
  
                          for (int i = 0; i < count; ++i)
                          {
                              Candidate cd = new Candidate(reader);
  
                              if (cd.Mobile != null)
                                  this.m_Candidates.Add(cd);
                          }
  
                          break;
                      }
              }
  
              this.StartTimer();
          }
  
          public Faction Faction
          {
              get
              {
                  return this.m_Faction;
              }
          }
          public List<Candidate> Candidates
          {
              get
              {
                  return this.m_Candidates;
              }
          }
          public ElectionState State
          {
              get
              {
                  return this.m_State;
              }
              set
              {
                  this.m_State = value;
                  this.m_LastStateTime = DateTime.UtcNow;
              }
          }
          public DateTime LastStateTime
          {
              get
              {
                  return this.m_LastStateTime;
              }
          }
          [CommandProperty(AccessLevel.GameMaster)]
          public ElectionState CurrentState
          {
              get
              {
                  return this.m_State;
              }
          }
          [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
          public TimeSpan NextStateTime
          {
              get
              {
                  TimeSpan period;
  
                  switch ( this.m_State )
                  {
                      default:
                      case ElectionState.Pending:
                          period = PendingPeriod;
                          break;
                      case ElectionState.Election:
                          period = VotingPeriod;
                          break;
                      case ElectionState.Campaign:
                          period = CampaignPeriod;
                          break;
                  }
  
                  TimeSpan until = (this.m_LastStateTime + period) - DateTime.UtcNow;
  
                  if (until < TimeSpan.Zero)
                      until = TimeSpan.Zero;
  
                  return until;
              }
              set
              {
                  TimeSpan period;
  
                  switch ( this.m_State )
                  {
                      default:
                      case ElectionState.Pending:
                          period = PendingPeriod;
                          break;
                      case ElectionState.Election:
                          period = VotingPeriod;
                          break;
                      case ElectionState.Campaign:
                          period = CampaignPeriod;
                          break;
                  }
  
                  this.m_LastStateTime = DateTime.UtcNow - period + value;
              }
          }
          public void StartTimer()
          {
              this.m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), new TimerCallback(Slice));
          }
  
          public void Serialize(GenericWriter writer)
          {
              writer.WriteEncodedInt((int)0); // version
  
              Faction.WriteReference(writer, this.m_Faction);
  
              writer.Write((DateTime)this.m_LastStateTime);
              writer.WriteEncodedInt((int)this.m_State);
  
              writer.WriteEncodedInt(this.m_Candidates.Count);
  
              for (int i = 0; i < this.m_Candidates.Count; ++i)
                  this.m_Candidates[i].Serialize(writer);
          }
  
          public void AddCandidate(Mobile mob)
          {
              if (this.IsCandidate(mob))
                  return;
  
              this.m_Candidates.Add(new Candidate(mob));
              mob.SendLocalizedMessage(1010117); // You are now running for office.
          }
  
          public void RemoveVoter(Mobile mob)
          {
              if (this.m_State == ElectionState.Election)
              {
                  for (int i = 0; i < this.m_Candidates.Count; ++i)
                  {
                      List<Voter> voters = this.m_Candidates[i].Voters;
  
                      for (int j = 0; j < voters.Count; ++j)
                      {
                          Voter voter = voters[j];
  
                          if (voter.From == mob)
                              voters.RemoveAt(j--);
                      }
                  }
              }
          }
  
          public void RemoveCandidate(Mobile mob)
          {
              Candidate cd = this.FindCandidate(mob);
  
              if (cd == null)
                  return;
  
              this.m_Candidates.Remove(cd);
              mob.SendLocalizedMessage(1038031);
  
              if (this.m_State == ElectionState.Election)
              {
                  if (this.m_Candidates.Count == 1)
                  {
                      this.m_Faction.Broadcast(1038031); // There are no longer any valid candidates in the Faction Commander election.
  
                      Candidate winner = this.m_Candidates[0];
  
                      Mobile winMob = winner.Mobile;
                      PlayerState pl = PlayerState.Find(winMob);
  
                      if (pl == null || pl.Faction != this.m_Faction || winMob == this.m_Faction.Commander)
                      {
                          this.m_Faction.Broadcast(1038026); // Faction leadership has not changed.
                      }
                      else
                      {
                          this.m_Faction.Broadcast(1038028); // The faction has a new commander.
                          this.m_Faction.Commander = winMob;
                      }
  
                      this.m_Candidates.Clear();
                      this.State = ElectionState.Pending;
                  }
                  else if (this.m_Candidates.Count == 0) // well, I guess this'll never happen
                  {
                      this.m_Faction.Broadcast(1038031); // There are no longer any valid candidates in the Faction Commander election.
  
                      this.m_Candidates.Clear();
                      this.State = ElectionState.Pending;
                  }
              }
          }
  
          public bool IsCandidate(Mobile mob)
          {
              return (this.FindCandidate(mob) != null);
          }
  
          public bool CanVote(Mobile mob)
          {
              return (this.m_State == ElectionState.Election && !this.HasVoted(mob));
          }
  
          public bool HasVoted(Mobile mob)
          {
  
gt:             return (this.FindVoter(mob) != null);