/// <summary>
        /// Create a service object by the function parameters.
        /// </summary>
        /// <param name="serviceElement"></param>
        /// <param name="serviceInstanceType"></param>
        /// <param name="serviceTimeScheduled"></param>
        /// <returns></returns>
        private ServiceInstance CreateNewService(EnabledConfigurationElement enabledConfigurationElement,
                                                 DateTime serviceTimeScheduled,
                                                 SchedulingRuleElement activeSchedulingRule, int accountID)
        {
            //// Create new service list if needed.
            //if (!_scheduleTable.ContainsKey(accountServiceElement.Uses.Element.Name))
            //{
            //    _scheduleTable.Add(accountServiceElement.Uses.Element.Name, new ServiceList(accountServiceElement.Uses.Element));
            //}
            ServiceInstance service;

            try
            {
                service = Service.CreateInstance(enabledConfigurationElement, accountID);
            }
            catch (Exception ex)
            {
                Log.Write("Exception occured while performing CreateInstance.", ex);
                return(null);
            }

            service.StateChanged          += _stateChangedHandler;
            service.OutcomeReported       += _outcomeReportedHandler;
            service.ChildServiceRequested += _childServiceRequestedHandler;
            service.ActiveSchedulingRule   = activeSchedulingRule;
            service.TimeScheduled          = serviceTimeScheduled;

            return(service);
        }
        public ServiceInstanceInfo(ServiceInstance instance)
        {
            _accountID     = instance.AccountID;
            _instanceID    = instance.InstanceID;
            _priority      = instance.Priority;
            _config        = instance.Configuration;
            _rule          = instance.ActiveSchedulingRule;
            _timeStarted   = instance.TimeStarted;
            _timeScheduled = instance.TimeScheduled;
            _serviceUrl    = instance.ServiceUrl;

            if (instance.ParentInstance != null)
            {
                _parentInstanceData = new ServiceInstanceInfo(instance.ParentInstance);
            }
        }
        static void Main(string[] args)
        {
            Console.WriteLine("Edge Service Host v. {0}", Assembly.GetExecutingAssembly().GetName().Version);
            Console.WriteLine("===================================");
            Console.WriteLine();

            // Check command line
            if (args.Length < 1 || !args[0].StartsWith("/"))
            {
                Console.WriteLine("Please start the program with a service name as an argument, e.g.: EdgeServiceHost.exe /ScheduleManager");
                Console.ReadLine();
                return;
            }
            string serviceName = args[0].Substring(1);

            bool  firstInstance = false;
            Mutex mutex         = new Mutex(false, String.Format("Global\\EdgeServiceHost-{0}", serviceName), out firstInstance);

            if (!firstInstance)
            {
                Log.Write(typeof(EdgeServiceHost).Name, String.Format("Trying to start a service host which is already running {0}; exiting.", serviceName), LogMessageType.Information);
                return;
            }

            // Check if the service exists
            ServiceElement serviceToRun = ServicesConfiguration.Services.GetService(serviceName);

            if (serviceToRun == null)
            {
                Console.WriteLine("Invalid service name (" + serviceName + " ). Press any key to exit.");
                Console.ReadLine();
                return;
            }

            // Init the service
            Console.WriteLine("Initializing {0}...", serviceToRun.Name);

            ServiceInstance       instance;
            SchedulingRuleElement alwaysOn;

            try
            {
                instance = Service.CreateInstance(serviceToRun);
                alwaysOn = new SchedulingRuleElement();
                alwaysOn.CalendarUnit         = CalendarUnit.AlwaysOn;
                instance.ActiveSchedulingRule = alwaysOn;
                instance.StateChanged        += new EventHandler <ServiceStateChangedEventArgs>(instance_StateChanged);
                instance.Initialize();
            }
            catch (Exception ex)
            {
                Log.Write(typeof(EdgeServiceHost).Name, String.Format("Failed to initialize the service. Service name: {0}.", serviceToRun.Name), ex);
                Console.WriteLine(String.Format("Failed to initialize the service. Service name: {0}. + Exception message: {1}", serviceToRun.Name, ex.Message.ToString()));
                Console.ReadLine();
                return;
            }

            // Wait for exit input
            while (Console.ReadKey().Key != ConsoleKey.Escape)
            {
                ;
            }

            // Abort the service if it is still running
            if (instance.State != ServiceState.Ended)
            {
                Console.WriteLine("\nAborting {0}...", serviceToRun.Name);

                try
                {
                    instance.Abort();
                }
                catch (Exception ex)
                {
                    //Log.Write(typeof(EdgeServiceHost).Name, String.Format("Could not abort {0}.", instance.Configuration.Name), ex);
                }
            }
        }
        /// <summary>
        /// Add the service to scheduleTable.
        /// </summary>
        /// <remarks>We schedule the table for next day.
        /// For example on sunday 23:00 we schedule the table for monday.</remarks>
        /// <param name="serviceElement">The service to add</param>
        /// <param name="rule">The specific rule of the service that will add for this service instance.</param>
        /// <param name="childService">If we add a service request this service is the requested child service to schedule.</param>
        //      private void AddServiceRule(AccountServiceElement accountServiceElement,
        //	SchedulingRuleElement rule, ServiceInstance childService, int accountID)
        private void AddServiceRule(AccountServiceElement accountServiceElement,
                                    SchedulingRuleElement rule, ServiceInstance childService, int accountID)
        {
            ServiceInstance service;
            DateTime        serviceScheduledTime;

            // ExactTimes case
            if (rule.ExactTimes.Length > 0)
            {
                foreach (TimeSpan hour in rule.ExactTimes)
                {
                    // Convet TimeSpan to datetime.
                    // We schedule the table for next day - we add 1 day.

                    if (!rule.NextDay)
                    {
                        serviceScheduledTime = DateTime.Today;
                        serviceScheduledTime = serviceScheduledTime.Add(hour);

                        // The service pass is deviation time.
                        if ((rule.MaxDeviation.TotalMilliseconds > 0) &&
                            (DateTime.Now - serviceScheduledTime > rule.MaxDeviation))
                        {
                            continue;
                        }
                    }
                    else
                    {
                        serviceScheduledTime = DateTime.Today.AddDays(1);
                        serviceScheduledTime = serviceScheduledTime.Add(hour);
                    }

                    if (childService == null)
                    {
                        service = CreateNewService(accountServiceElement, serviceScheduledTime, rule, accountID);
                    }
                    else
                    {
                        service = childService;
                    }

                    // Add the service to the schedule table.
                    if (service != null)
                    {
                        _scheduleTable.AddService(service);
                    }

                    // Relevent for service request which have rules that were
                    // suppose to be shceduled eariler.
                    if (serviceScheduledTime < DateTime.Now)
                    {
                        // TODO: maybe add this log to error file.
                        // TODO: might need more info on the log like service runtime ID
                        //Log.Write(String.Format("The service {0} of account {1} can't schedule the service cause its scheduled for eariler time."
                        //     , accountServiceElement != null ? accountServiceElement.Uses.Element.Name : childService.Configuration.Name,
                        //     accountServiceElement != null ? string.Empty : childService.AccountID.ToString()),
                        //     LogMessageType.Warning);

                        continue;
                    }
                }
            }
            else // Frequency case
            {
                // Get last run from the DB for this service.
                DateTime lastServiceRun = GetLastServiceRun
                                              (accountServiceElement != null ? accountServiceElement.Uses.Element.Name : childService.Configuration.Name);

                // Init time with the end of the next day.
                DateTime nextDayEnd = DateTime.Today.AddDays(2).AddTicks(-1);

                if (lastServiceRun.AddMinutes(rule.Frequency.TotalMinutes) > DateTime.Now)
                {
                    serviceScheduledTime = lastServiceRun.AddMinutes(rule.Frequency.TotalMinutes);
                }
                else
                {
                    serviceScheduledTime = DateTime.Now;
                }

                // We keep to schedule sevices till we pass the current day.
                while (serviceScheduledTime < nextDayEnd)
                {
                    if (childService == null)
                    {
                        service = CreateNewService(accountServiceElement, serviceScheduledTime, rule, accountID);
                    }
                    else
                    {
                        service = childService;
                    }

                    // Add the service to the schedule table.
                    if (service != null)
                    {
                        _scheduleTable.AddService(service);
                    }

                    // Increase time with Frequency value.
                    serviceScheduledTime = serviceScheduledTime.AddMinutes(rule.Frequency.TotalMinutes);
                }
            }
        }
        /// <summary>
        /// Create a service According to the service rule.
        /// </summary>
        /// <param name="accountServiceElement"></param>
        /// <param name="accountID"></param>
        /// <param name="childService"></param>
        /// <param name="rule"></parammmmm>
        private void HandleRule(AccountServiceElement accountServiceElement, int accountID, ServiceInstance childService, SchedulingRuleElement rule)
        {
            switch (rule.CalendarUnit)
            {
            case CalendarUnit.ReRun:
                if (ScheduleConvertor.CheckFullSchedule(rule.FullSchedule))
                {
                    AddServiceRule(accountServiceElement, rule, childService, accountID);
                }

                break;

            // Month
            case CalendarUnit.Month:
                // Loop on all the days values in the rule.
                foreach (int day in rule.SubUnits)
                {
                    if (day == DateTime.Now.Day)
                    {
                        AddServiceRule(accountServiceElement, rule, childService, accountID);
                    }
                }
                break;

            // Week
            case CalendarUnit.Week:
                // Loop on all the days values in the rule.
                foreach (int day in rule.SubUnits)
                {
                    // DayOfWeek return values of 0-6 and because of it we -1 on left side.
                    if (day == (int)DateTime.Now.DayOfWeek + 1)
                    {
                        AddServiceRule(accountServiceElement, rule, childService, accountID);
                    }
                }
                break;

            // Day
            case CalendarUnit.Day:
                AddServiceRule(accountServiceElement, rule, childService, accountID);
                break;

            // AlwaysOn
            case CalendarUnit.AlwaysOn:

                ServiceInstance service;
                if (childService == null && _firstRun)
                {
                    try
                    {
                        service = CreateNewService(accountServiceElement, DateTime.Now, rule, accountID);
                    }
                    catch (Exception ex)
                    {
                        Log.Write(string.Format("Can't add the always on service {0} for accoutID {1}", accountServiceElement.ToString(), accountID.ToString()), ex, LogMessageType.Error);
                        return;
                    }
                }
                else
                {
                    service = childService;
                }

                // Add the service to the scheduleTable.
                if (service != null)
                {
                    _scheduleTable.AddService(service);
                }
                break;

            // Never should be here
            default:
                Log.Write(String.Format("The service {0}  don't have calendar unit, can't schedule the service."
                                        , accountServiceElement != null ? accountServiceElement.Uses.Element.Name : childService.Configuration.Name), LogMessageType.Warning);
                break;
            }
        }