/// <summary>
        /// Mark tasks claimed.
        /// </summary>
        public GXTasksClaimResponse(GXClaimedTask[] tasks)
		{
            if (tasks != null)
            {
                int pos = -1;
                this.Tasks = new GXClaimedTask[tasks.Length];
                for (int i = 0; i < tasks.Length; i++)
                {
                    this.Tasks[++pos] = tasks[i];
                }
            }
		}
 public void ExecuteTransaction(GXClaimedTask taskinfo)
 {            
     object target;
     if (taskinfo.Task.TargetType == TargetType.Device)
     {
         target = Device;
     }
     else
     {                
         target = Device.FindItemByID(taskinfo.Task.TargetID);
     }
     if (target is GXDevice)
     {
         if (taskinfo.Task.TaskType == TaskType.Read)
         {
             (target as GXDevice).Read();
         }
     }
     else if (target is GXCategory)
     {
         if (taskinfo.Task.TaskType == TaskType.Read)
         {
             (target as GXCategory).Read();
         }
     }
     else if (target is GXTable)
     {
         if (!string.IsNullOrEmpty(taskinfo.Task.Data))
         {
             Gurux.Device.Editor.IGXPartialRead pr = target as Gurux.Device.Editor.IGXPartialRead;
             string[] parameters = taskinfo.Task.Data.Split(new char[] { ';' });                    
             pr.Type = (PartialReadType) Convert.ToInt32(parameters[0]);
             //Read by entry (index and count)..
             if (pr.Type == PartialReadType.Entry)
             { 
                 int start = Convert.ToInt32(parameters[1]);
                 int end = Convert.ToInt32(parameters[2]);
                 //Read all values.
                 if (start == 0 && end == 0)
                 {
                     pr.Type = PartialReadType.All;
                 }
                 else
                 {
                     pr.Start = start;
                     pr.End = end;
                 }
             }
             //Read by range (between start and end time).
             else if (pr.Type == PartialReadType.Range)
             {
                 pr.Start = Convert.ToDateTime(parameters[1]);
                 pr.End = Convert.ToDateTime(parameters[2]);
             }
             else
             {
                 throw new ArgumentException("Invalid type.");
             }
         }
         //In default read new values.
         if (taskinfo.Task.TaskType == TaskType.Read)
         {
             (target as GXTable).Read();
         }
     }
     else if (target is GXProperty)
     {
         if (taskinfo.Task.TaskType == TaskType.Read)
         {
             (target as GXProperty).Read();
         }
     }
     else
     {
         throw new ArgumentException("Unknown target.");
     }
 }
        /// <summary>
        /// Load device template and connect to the device.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="taskinfo"></param>
        public void Connect(string path, GXClaimedTask taskinfo)
        {
            ExecutedTask = taskinfo;
            //If already connected.
            if (Device != null)
            {
                UpdateParameters();
                if ((Device.Status & DeviceStates.Connected) == 0)
                {
                    Device.Connect();
                }
                return;
            }
            DeviceList = new GXDeviceList();
            DeviceList.OnError += new Gurux.Common.ErrorEventHandler(DeviceList_OnError);
            DeviceList.OnUpdated += new ItemUpdatedEventHandler(DeviceList_OnUpdated);                        
            GXDeviceGroup group = new GXDeviceGroup();
            DeviceList.DeviceGroups.Add(group);
            TargetDirectory = path;
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            AppDomain.CurrentDomain.TypeResolve += new ResolveEventHandler(CurrentDomain_TypeResolve);
            GXDeviceList.Update(path);
            string filename = Path.Combine(path, taskinfo.Device.ProfileGuid + ".gxp");            
            Device = GXDevice.Load(filename);
            Device.ID = taskinfo.Device.Id;
            group.Devices.Add(Device);
            Device.Name = taskinfo.Device.Name;
            //taskinfo.Device.AutoConnect;
            // ForcePerPropertyRead
            Device.UpdateInterval = taskinfo.Device.UpdateInterval;
            Device.WaitTime = taskinfo.Device.WaitTime;
            Device.ResendCount = taskinfo.Device.ResendCount;
            Device.DisabledActions = taskinfo.Device.DisabledActions;

            /* TODO:
            Device.FailTryCount = taskinfo.Device.FailTryCount;
            Device.FailWaitTime = taskinfo.Device.FailWaitTime;
            Device.ConnectionTryCount = taskinfo.Device.ConnectionTryCount;
            Device.ConnectionFailWaitTime = taskinfo.Device.ConnectionFailWaitTime;
              */

            //Update parameters.
            UpdateParameters();

            //Load medias to this assembly domin.
            Gurux.Communication.GXClient.GetAvailableMedias();
            if (taskinfo.Device.TraceLevel != System.Diagnostics.TraceLevel.Off)
            {
                Device.Trace = taskinfo.Device.TraceLevel;
                Device.OnTrace += new TraceEventHandler(Device_OnTrace);
            }
            Exception lastException = null;
            int pos = -1;
            Gurux.Common.IGXMedia media = null;
            foreach (var it in taskinfo.MediaSettings)
            {
                try
                {
                    ++pos;
                    //If media is changed.
                    if (media == null || media.MediaType != taskinfo.MediaSettings[pos].Key)
                    {
                        media = Device.GXClient.SelectMedia(taskinfo.MediaSettings[pos].Key);
                        Device.GXClient.AssignMedia(media);
                    }
                    media.Settings = taskinfo.MediaSettings[pos].Value.Value;                    
                    lastException = null;                        
                    Device.Connect();
                    break;
                }
                catch (Exception ex)
                {
                    //If connection fails try next redundant connectio.
                    lastException = ex;                    
                }
            }
            if (lastException != null)
            {
                throw lastException;
            }
        }
        /// <summary>
        /// Mark task(s) as claimed.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public GXTasksClaimResponse Post(GXTasksClaimRequest request)
        {
            List<GXEventsItem> events = new List<GXEventsItem>();
            List<GXClaimedTask> infoList = new List<GXClaimedTask>();
            AppHost host = this.ResolveService<AppHost>();
            Guid guid;
            IAuthSession s = this.GetSession(false);
            if (!GXBasicAuthProvider.IsGuid(s.UserAuthName, out guid))
            {
                throw new ArgumentException("Access denied.");
            }
            lock (Db)
            {                                
                DateTime claimTime = DateTime.Now;
                foreach (ulong it in request.TaskIDs)
                {
                    GXAmiDataCollector collector = null;
                    //Try to get wanted task. If that is taken get next available task.
                    List<GXAmiTask> tasks = Db.Select<GXAmiTask>(q => q.Id == it && q.ClaimTime == null);
                    //Make sure that no one else is has not claim the task.
                    GXAmiTask task = null;
                    bool wantedTask = tasks.Count != 0;
                    if (wantedTask)
                    {
#if !SS4
                        task = Db.GetById<GXAmiTask>(it);
#else
                        task = Db.SingleById<GXAmiTask>(it);
#endif
                    }
                    else
                    {
                        tasks = Db.Select<GXAmiTask>(q => q.ClaimTime == null);
                        if (tasks.Count != 0)
                        {
                            task = tasks[0];
                        }
                    }                                            
                    if (task != null)
                    {
                        task.Data = GetData(it, false);
                        task.SenderDataCollectorGuid = guid;
                        //If DC is clamiming the task for it self.
                        if (task.TargetDeviceID == null && task.DataCollectorGuid != Guid.Empty)
                        {
                            //DC can claim only own tasks.
                            if (task.DataCollectorGuid != guid)
                            {
                                throw new ArgumentException("Access denied.");
                            }
                            List<GXAmiDataCollector> collectors = Db.Select<GXAmiDataCollector>(q => q.Guid == guid);
                            if (collectors.Count != 1)
                            {
                                throw new ArgumentException("Access denied.");
                            }
                            collector = collectors[0];
                        }
                        else //If DC is claiming device task.
                        {                            
                            //Get list of DC that can access Device.
                            string query = string.Format("SELECT DISTINCT {0}.* FROM {0} INNER JOIN {1} ON ({0}.ID = {1}.DataCollectorId OR {1}.DataCollectorId IS NULL) WHERE DeviceID = {2} AND Guid = '{3}'",
                                        GuruxAMI.Server.AppHost.GetTableName<GXAmiDataCollector>(Db), 
                                        GuruxAMI.Server.AppHost.GetTableName<GXAmiDeviceMedia>(Db),
                                        task.TargetDeviceID.Value,
                                        guid.ToString().Replace("-", ""));
                            List<GXAmiDataCollector> collectors = Db.Select<GXAmiDataCollector>(query);
                            //If DC can't access task.
                            if (collectors.Count == 0)
                            {
                                throw new ArgumentException("Access denied.");
                            }
                            collector = collectors[0];
                        }
                        //Find device template Guid.
                        if (task.TargetDeviceID != null)
                        {
                            string query = string.Format("SELECT {0}.* FROM {0} INNER JOIN {1} ON {0}.ID = {1}.ProfileId WHERE {1}.ID = {2}",
                                GuruxAMI.Server.AppHost.GetTableName<GXAmiDeviceProfile>(Db),
                                GuruxAMI.Server.AppHost.GetTableName<GXAmiDevice>(Db),
                                task.TargetDeviceID.Value);
                            List<GXAmiDeviceProfile> profiles = Db.Select<GXAmiDeviceProfile>(query);
                            if (profiles.Count != 1)
                            {
                                throw new ArgumentException("Access denied.");
                            }
                            GXClaimedTask info = new GXClaimedTask();
                            if (!wantedTask)
                            {
                                info.Task = task;
                            }
                            info.DeviceProfile = profiles[0].Guid;
                            query = string.Format("SELECT {0}.* FROM {0} WHERE {0}.ID = {1}",
                                GuruxAMI.Server.AppHost.GetTableName<GXAmiDevice>(Db),
                                task.TargetDeviceID.Value);
                            List<GXAmiDevice> devices = Db.Select<GXAmiDevice>(query);
                            if (devices.Count != 1)
                            {
                                throw new ArgumentException("Access denied.");
                            }
                            info.Device = devices[0];
                            info.Device.Parameters = Db.Select<GXAmiParameter>(q => q.ParentID == info.Device.Id).ToArray();
                            info.Device.Categories = Db.Select<GXAmiCategory>(q => q.DeviceID == info.Device.Id).ToArray();
                            foreach (GXAmiCategory cat in info.Device.Categories)
                            {
                                cat.Parameters = Db.Select<GXAmiParameter>(q => q.ParentID == cat.Id).ToArray();
                                cat.Properties = Db.Select<GXAmiProperty>(q => q.ParentID == cat.Id).ToArray();
                                foreach (GXAmiProperty p in cat.Properties)
                                {
                                    p.Parameters = Db.Select<GXAmiParameter>(q => q.ParentID == p.Id).ToArray();
                                }
                            }
                            info.Device.Tables = Db.Select<GXAmiDataTable>(q => q.DeviceID == info.Device.Id).ToArray();
                            foreach (GXAmiDataTable table in info.Device.Tables)
                            {
                                table.Parameters = Db.Select<GXAmiParameter>(q => q.ParentID == table.Id).ToArray();
                                table.Columns = Db.Select<GXAmiProperty>(q => q.ParentID == table.Id).ToArray();
                                foreach (GXAmiProperty p in table.Columns)
                                {
                                    p.Parameters = Db.Select<GXAmiParameter>(q => q.ParentID == p.Id).ToArray();
                                }
                            }
                            info.Device.ProfileGuid = profiles[0].Guid;
                            List<GXAmiDeviceMedia> Medias = Db.Select<GXAmiDeviceMedia>(q => q.DeviceId == info.Device.Id);
                            foreach(GXAmiDeviceMedia it2 in Medias)
                            {
                                if (it2.DataCollectorId == null || it2.DataCollectorId == collector.Id)
                                {
                                    info.MediaSettings.Add(new KeyValuePair<string, KeyValuePair<string, string>>(it2.Name, new KeyValuePair<string, string>(it2.Name, it2.Settings)));
                                }
                            }
                            info.Data = task.Data;
                            infoList.Add(info);
                        }
                        else //DC claims the task to itself.
                        {
                            GXClaimedTask info = new GXClaimedTask();
                            if (task.TargetType == TargetType.Media)
                            {
                                if (task.TaskType == TaskType.MediaOpen)
                                {
                                    string[] data = task.Data.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                                    info.MediaSettings.Clear();
                                    info.MediaSettings.Add(new KeyValuePair<string, KeyValuePair<string, string>>(data[0], new KeyValuePair<string, string>(data[1], data[2])));                                    
                                    task.Data = null;
                                }
                                else if (task.TaskType == TaskType.MediaClose)
                                {
                                    string[] data = task.Data.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                                    info.MediaSettings.Clear();
                                    info.MediaSettings.Add(new KeyValuePair<string, KeyValuePair<string, string>>(data[0], new KeyValuePair<string, string>(data[1], "")));                                    
                                    task.Data = null;
                                }
                                else if (task.TaskType == TaskType.MediaWrite)
                                {
                                    string[] data = task.Data.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                                    info.MediaSettings.Clear();
                                    info.MediaSettings.Add(new KeyValuePair<string, KeyValuePair<string, string>>(data[0], new KeyValuePair<string, string>(data[1], "")));
                                    task.Data = data[2];
                                }
                                else if (task.TaskType == TaskType.MediaGetProperty)
                                {
                                    string[] data = task.Data.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                                    info.MediaSettings.Clear();
                                    info.MediaSettings.Add(new KeyValuePair<string, KeyValuePair<string, string>>(data[0], new KeyValuePair<string, string>(data[1], "")));
                                    task.Data = data[2];
                                }
                                else if (task.TaskType == TaskType.MediaSetProperty)
                                {
                                    string[] data = task.Data.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                                    info.MediaSettings.Clear();
                                    info.MediaSettings.Add(new KeyValuePair<string, KeyValuePair<string, string>>(data[0], new KeyValuePair<string, string>(data[1], "")));
                                    task.Data = data[2] + Environment.NewLine + data[3];
                                }
                            }
                            info.DataCollectorID = collector.Id;
                            info.Data = task.Data;
                            infoList.Add(info);
                        }
                        task.ClaimTime = claimTime;
                        task.State = TaskState.Processing;
                        task.DataCollectorID = collector.Id;
                        task.DataCollectorGuid = guid;
                        task.SenderDataCollectorGuid = guid;
                        Db.Update(task);
                        events.Add(new GXEventsItem(ActionTargets.Task, Actions.Edit, task));                        
                    }
                }
            }                        
            //Notify that task is claimed.                        
            host.SetEvents(Db, this.Request, 0, events);
            return new GXTasksClaimResponse(infoList.ToArray());
        }
 private void HandleDevice(GXClaimedInfo info, GXProxyClass pc, ref string path, ref bool leaveConnectionOpen, GXClaimedTask taskinfo)
 {
     try
     {
         //If device template is not loaded yet.
         if (path == null)
         {
             path = Path.Combine(Gurux.Common.GXCommon.ApplicationDataPath, "Gurux");
             if (!Directory.Exists(path))
             {
                 Directory.CreateDirectory(path);
                 Gurux.Common.GXFileSystemSecurity.UpdateDirectorySecurity(path);
             }
             path = Path.Combine(path, "Gurux.DeviceSuite");
             if (!Directory.Exists(path))
             {
                 Directory.CreateDirectory(path);
                 Gurux.Common.GXFileSystemSecurity.UpdateDirectorySecurity(path);
             }
             path = Path.Combine(path, "DeviceProfiles");
             if (!Directory.Exists(path))
             {
                 Directory.CreateDirectory(path);
                 Gurux.Common.GXFileSystemSecurity.UpdateDirectorySecurity(path);
             }
             path = Path.Combine(path, taskinfo.DeviceProfile.ToString());
             //Load Device template if not loaded yet.                                 
             if (!Directory.Exists(path))
             {
                 Directory.CreateDirectory(path);
                 Gurux.Common.GXFileSystemSecurity.UpdateDirectorySecurity(path);
                 byte[] data = DC.GetDeviceProfilesData(taskinfo.DeviceProfile);
                 GXDeviceProfile type = pc.Import(data, path);
                 if (!(type is GXPublishedDeviceProfile))
                 {
                     File.Copy(type.Path, Path.Combine(path, taskinfo.DeviceProfile.ToString() + ".gxp"), true);
                 }
             }
         }
     }
     catch (Exception ex)
     {
         path = null;
         if (Directory.Exists(path))
         {
             Directory.Delete(path, true);
         }
         lock (info.Exceptions)
         {
             info.Exceptions.Add(taskinfo, ex);
             taskinfo.Task.State = TaskState.Failed;
         }
     }
     try
     {
         //Save executed task. This is used if error occures.                                    
         pc.Connect(path, taskinfo);
         //Read or write device.
         if (taskinfo.Task.TaskType == TaskType.Read ||
             taskinfo.Task.TaskType == TaskType.Write)
         {
             System.Diagnostics.Debug.WriteLine("DC start to read target: " + taskinfo.Task.Id.ToString() + " " + taskinfo.Task.TargetDeviceID.ToString());
             pc.ExecuteTransaction(taskinfo);
             taskinfo.Task.State = TaskState.Succeeded;
             System.Diagnostics.Debug.WriteLine("DC end reading target: " + taskinfo.Task.Id.ToString() + " " + Guid.ToString());                                        
         }
         else if (taskinfo.Task.TaskType == TaskType.StartMonitor)
         {
             leaveConnectionOpen = true;
             pc.StartMonitoring();
             taskinfo.Task.State = TaskState.Succeeded;
         }
         else if (taskinfo.Task.TaskType == TaskType.StopMonitor)
         {
             leaveConnectionOpen = false;
             pc.StopMonitoring();
             taskinfo.Task.State = TaskState.Succeeded;
         }
         else
         {
             throw new Exception("Invalid task type.");
         }
     }
     catch (Exception ex)
     {
         lock (info.Exceptions)
         {
             info.Exceptions.Add(taskinfo, ex);
             taskinfo.Task.State = TaskState.Failed;
         }
         if (m_Error != null)
         {
             m_Error(this, ex);
         }
     }
 }
 /// <summary>
 /// Save executed tasks so they can be retreaved if app is restarted.
 /// </summary>
 /// <remarks>
 /// Example monitoring uses this.
 /// </remarks>
 static void SaveExecutedTask(Guid guid, GXClaimedTask task)
 {
     XmlWriterSettings settings = new XmlWriterSettings();
     settings.Indent = true;
     settings.Encoding = System.Text.Encoding.UTF8;
     settings.CloseOutput = true;
     settings.CheckCharacters = false;
     System.Runtime.Serialization.DataContractSerializer x = new System.Runtime.Serialization.DataContractSerializer(typeof(GXClaimedTask));
     using (XmlWriter writer = XmlWriter.Create(guid.ToString() + "executingTask.xml", settings))
     {
         x.WriteObject(writer, task);
     }
 }