/// <summary>
        /// Wait new tasks and and create instance from DC if not created yet.
        /// </summary>
        void Run()
        {            
            //Read tasks that was prosessed when app was closed.
            //This is used to start example monitoring again.
            GXClaimedTask executedTask = LoadExecutedTask(this.Guid);
            if (executedTask != null)
            {
                if (executedTask.Task.TaskType == TaskType.StartMonitor)
                {
                    TaskModified.Set();
                }
            }
            else
            {
                GXAmiTask[] pendingTasks = DC.GetTasks(TaskState.Pending, false);
                if (pendingTasks.Length != 0)
                {
                    DC_OnTasksAdded(DC, pendingTasks);
                }
            }
            //Save device threads so we can wait whem on close.
            while (true)
            {
                List<EventWaitHandle> events = new List<EventWaitHandle>();
                events.Add(Closing);
                events.Add(TaskModified);
                foreach (GXClaimedInfo it in ClaimedTasks.Values.ToArray())
                {
                    events.Add(it.TaskExecuted);
                }

                int ret = EventWaitHandle.WaitAny(events.ToArray());
                //If closing.
                if (ret == 0)
                {
                    break;
                }                
                //If new task added.
                if (ret == 1)
                {
                    System.Diagnostics.Debug.WriteLine("DC task added: " + Guid.ToString());
                    //Get new task
                    GXClaimedTask taskinfo = executedTask;
                    executedTask = null;
                    lock (UnclaimedTasks)
                    {
                        for (int pos = 0; pos != UnclaimedTasks.Count; ++pos)
                        {
                                GXAmiTask task = UnclaimedTasks[pos];
                                //New task added.
                                if (task.State == TaskState.Pending)
                                {
                                    lock (UnclaimedTasks)
                                    {
                                        bool idle = true;
                                        //If task is sent to the device
                                        if (task.TargetDeviceID != null)
                                        {
                                            idle = !ClaimedTasks.ContainsKey(task.TargetDeviceID.Value) ||
                                                ClaimedTasks[task.TargetDeviceID.Value].ClaimedTasks.Count == 0;
                                        }
                                        else //If task is sent to the DC.
                                        {
                                            idle = !ClaimedTasks.ContainsKey(task.DataCollectorGuid) ||
                                                ClaimedTasks[task.DataCollectorGuid].ClaimedTasks.Count == 0;
                                        }
                                        //If collector is reading do not claim task before collector is finished reading.
                                        if (idle)
                                        {
                                            try
                                            {
                                                taskinfo = DC.ClaimTask(task);
                                                //If other DC is claimed the task.
                                                if (taskinfo == null || task.Id != taskinfo.Task.Id)
                                                {
                                                    //Remove task that was asked, but failed.
                                                    UnclaimedTasks.Remove(task);
                                                    //Remove executed task.
                                                    if (taskinfo != null && task.Id != taskinfo.Task.Id)
                                                    {
                                                        UnclaimedTasks.Remove(taskinfo.Task);
                                                        if (taskinfo.Task.State == TaskState.Processing)
                                                        {
                                                            System.Diagnostics.Debug.Assert(false);
                                                        }
                                                        task = taskinfo.Task;
                                                    }
                                                }
                                                else //DC claimed task.
                                                {
                                                    task = taskinfo.Task;
                                                    UnclaimedTasks.Remove(task);
                                                }
                                                if (taskinfo != null)
                                                {
                                                    //This should be newer happend.
                                                    if (task.State == TaskState.Processing)
                                                    {
                                                        System.Diagnostics.Debug.Assert(false);
                                                    }
                                                    System.Diagnostics.Debug.WriteLine("DC Start to process task: " + Guid.ToString() + " " + task.Id.ToString() + " " + task.TargetDeviceID.ToString());
                                                    if (m_TasksClaimed != null)
                                                    {
                                                        m_TasksClaimed(this, new GXAmiTask[] { task });
                                                    }
                                                }
                                                else
                                                {
                                                    System.Diagnostics.Debug.WriteLine("DC Failed to get task: " + Guid.ToString() + " " + task.Id.ToString());
                                                }
                                                break;
                                            }
                                            catch (Exception ex)
                                            {
                                                if (m_Error != null)
                                                {
                                                    m_Error(this, ex);
                                                }
                                            }
                                        }
                                        else//If task is processed. Wait until task is executed and read again...
                                        {
                                            System.Diagnostics.Debug.WriteLine("DC is already processing task: " + Guid.ToString());
                                            if (task.TargetDeviceID != null)
                                            {
                                                ClaimedTasks[task.TargetDeviceID].TaskExecuted.WaitOne(50000);
                                            }
                                            else
                                            {
                                                ClaimedTasks[task.DataCollectorGuid].TaskExecuted.WaitOne(50000);
                                            }
                                            break;
                                        }
                                    }
                                }
                        }
                    }
                    //If new task is claimed.
                    if (taskinfo != null)
                    {
                        if (taskinfo.Task.TargetDeviceID != null)
                        {
                            SaveExecutedTask(this.Guid, taskinfo);
                            GXClaimedInfo dcinfo = null;
                            //If task is sent to existing device.
                            if (ClaimedTasks.ContainsKey(taskinfo.Task.TargetDeviceID.Value))
                            {
                                dcinfo = ClaimedTasks[taskinfo.Task.TargetDeviceID.Value];
                                lock (dcinfo.ClaimedTasks)
                                {
                                    dcinfo.ClaimedTasks.Add(taskinfo);
                                    dcinfo.NewTask.Set();
                                }
                            }
                            else//If task is sent to new device.
                            {
                                dcinfo = new GXClaimedInfo();
                                dcinfo.ClaimedTasks.Add(taskinfo);                                
                                ClaimedTasks.Add(taskinfo.Task.TargetDeviceID.Value, dcinfo);
                                Thread thread = new Thread(new ParameterizedThreadStart(DeviceCollector));
                                thread.Start(dcinfo);
                                dcinfo.WorkThread = thread;
                            }                            
                        }
                        //Task is send to Media
                        else if (taskinfo.Task.TargetType == TargetType.Media)
                        {
                            GXClaimedInfo dcinfo = null;
                            if (ClaimedTasks.ContainsKey(taskinfo.Task.DataCollectorGuid))
                            {
                                dcinfo = ClaimedTasks[taskinfo.Task.DataCollectorGuid];
                                lock (dcinfo.ClaimedTasks)
                                {
                                    dcinfo.ClaimedTasks.Add(taskinfo);
                                    dcinfo.NewTask.Set();
                                }
                            }
                            else
                            {
                                dcinfo = new GXClaimedInfo();
                                dcinfo.ClaimedTasks.Add(taskinfo);                                
                                ClaimedTasks.Add(taskinfo.Task.DataCollectorGuid, dcinfo);
                                Thread thread = new Thread(new ParameterizedThreadStart(DeviceCollector));
                                thread.Start(dcinfo);
                                dcinfo.WorkThread = thread;
                            }
                        }
                    }
                }
                else
                {
                    ret -= 2;
                    GXClaimedInfo c = ClaimedTasks[ClaimedTasks.Keys.ElementAt(ret)];                    
                    c.TaskExecuted.Reset();
                    System.Diagnostics.Debug.WriteLine("Task handled: " + c.ClaimedTasks[0].Task.Id.ToString());
                    foreach (GXClaimedTask it2 in c.ClaimedTasks)
                    {
                        GXAmiTask task = it2.Task;                        
                        //This should be newer happend.
                        if (task.State == TaskState.Processing)
                        {
                            System.Diagnostics.Debug.Assert(false);
                        }
                        //Remove task after successful reading.
                        if (task.State == TaskState.Succeeded)
                        {
                            lock (c.ClaimedTasks)
                            {
                                c.ClaimedTasks.Remove(it2);                                
                            }
                            try
                            {
                                DC.RemoveTask(task);
                                //Close thread if device task is executed and connection is not leave open. 
                                if ( task.TaskType != TaskType.StartMonitor)
                                {
                                    if (task.TargetDeviceID != null)
                                    {
                                        c.Closing.Set();
                                        ClaimedTasks.Remove(task.TargetDeviceID.Value);                                        
                                    }
                                    else if (task.TaskType == TaskType.MediaClose)//if DC task is executed.
                                    {
                                        c.Closing.Set();
                                        ClaimedTasks.Remove(task.DataCollectorGuid);                                        
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                if (m_Error != null)
                                {
                                    m_Error(this, ex);
                                }
                            }
                            lock (UnclaimedTasks)
                            {
                                //Search next unclaimed task and execute it.
                                foreach (GXAmiTask ut in UnclaimedTasks)
                                {
                                    if (ut.State == TaskState.Pending)
                                    {
                                        TaskModified.Set();
                                        break;
                                    }
                                }
                            }
                            //System.Diagnostics.Debug.WriteLine("Wait next task.");
                            break; //Break here because task is removed.                                    
                        }
                        else if (task.State == TaskState.Timeout)
                        {
                            try
                            {
                                lock (c.ClaimedTasks)
                                {
                                    c.ClaimedTasks.Remove(it2);
                                }
                                DC.AddDeviceError(task, new TimeoutException(), 1);
                                //Remove failed task.
                                DC.RemoveTask(task);
                            }
                            catch (Exception ex)
                            {
                                if (m_Error != null)
                                {
                                    m_Error(this, ex);
                                }
                            }
                            break; //Break here because task is removed.      
                        }
                        else if (task.State == TaskState.Failed)
                        {
                            try
                            {
                                lock (c.ClaimedTasks)
                                {
                                    c.ClaimedTasks.Remove(it2);
                                }
                                foreach (var it in c.Exceptions)
                                {
                                    DC.AddDeviceError(it.Key.Task, it.Value, 1);
                                    /*
                                    //If device is caused the error.
                                    if (it.Key.Task.TargetDeviceID.HasValue)
                                    {
                                        DC.AddDeviceError(it.Key.Task, it.Value, 1);
                                    }
                                    //If DC is caused the error.
                                    else if (it.Key.Task.DataCollectorID != 0)
                                    {
                                        DC.AddDeviceError(it.Key.Task, it.Value, 1);
                                    }
                                    else
                                    {
                                        throw new Exception("Unknown target.");
                                    }
                                     * */
                                }
                                c.Exceptions.Clear();
                                //Remove failed task.
                                DC.RemoveTask(task);
                            }
                            catch (Exception ex)
                            {
                                if (m_Error != null)
                                {
                                    m_Error(this, ex);
                                }
                            }
                            break; //Break here because task is removed.      
                        }
                    }
                }
            }
            //Tell all collector threads to close.
            List<Thread> threads = new List<Thread>();
            foreach(GXClaimedInfo it in ClaimedTasks.Values)
            {                
                it.Closing.Set();
                threads.Add(it.WorkThread);
            }
            //Wait until threads are closed.
            foreach (Thread it in threads)
            {
                it.Join();
            }            
        }
 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);
         }
     }
 }