/// <summary>
 /// Overrides the method used to provide basic behaviour for selecting editor.
 /// Shows our custom control for editing the value.
 /// </summary>
 /// <param name="context">The context of the editing control</param>
 /// <param name="provider">A valid service provider</param>
 /// <param name="value">The current value of the object to edit</param>
 /// <returns>The new value of the object</returns>
 public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value)
 {                       
     if (context == null || context.Instance == null || provider == null)
     {
         return base.EditValue(context, provider, value);
     }            
     //Show macro dialog.
     GXMediaType type = (GXMediaType)value;
     Gurux.Communication.GXClient cl = new Gurux.Communication.GXClient();
     Gurux.Common.IGXMedia media = cl.SelectMedia(type.Name) as Gurux.Common.IGXMedia;
     if (media != null)
     {
         media.Settings = type.DefaultMediaSettings;
         if (media.Properties(null))
         {
             type.DefaultMediaSettings = media.Settings;
         }
     }
     return value;
 }        
        /// <summary>
        /// Device collector thread.
        /// </summary>
        /// <param name="target"></param>
        void DeviceCollector(object target)
        {            
            GXClaimedInfo info = target as GXClaimedInfo;            
            string pathToDll = this.GetType().Assembly.CodeBase;
            // Create an Application Domain:
            AppDomainSetup domainSetup = new AppDomainSetup { PrivateBinPath = pathToDll };
            string dir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + Path.DirectorySeparatorChar);
            Dictionary<string, IGXMedia> medias = new Dictionary<string,IGXMedia>();
            Guid loadedDeviceProfiles = Guid.Empty;
            System.AppDomain td = AppDomain.CreateDomain("DC_Domain", null, domainSetup);
            GXProxyClass pc = (GXProxyClass)(td.CreateInstanceFromAndUnwrap(pathToDll, typeof(GXProxyClass).FullName));
            GXAmiEventListener listener = new GXAmiEventListener(this, pc, DC);            
            string path = null;
            List<GXAmiTask> executedTasks = new List<GXAmiTask>();
            //Connection is leave open if meter is monitored.
            bool leaveConnectionOpen = false;
            GXClaimedTask taskinfo = null;            
            while (!info.Closing.WaitOne(1))
            {
                try
                {
                    while (!info.Closing.WaitOne(1))
                    {
                        bool moreTasks = false;
                        //Check is there more tasks to execute otherwice close the connection.
                        lock (info.ClaimedTasks)
                        {
                            foreach(var it in info.ClaimedTasks)
                            {
                                if (it.Task.State == TaskState.Pending)
                                {
                                    moreTasks = true;
                                }
                            }
                            //Close connection if meter is not monitored.
                            if (!moreTasks && !leaveConnectionOpen)
                            {
                                try
                                {
                                    pc.Disconnect();
                                }
                                catch (Exception ex)
                                {
                                    lock (info.Exceptions)
                                    {
                                        //Taskinfo is null in disconnecting.
                                        if (taskinfo != null)
                                        {
                                            info.Exceptions.Add(taskinfo, ex);
                                            taskinfo.Task.State = TaskState.Failed;
                                            info.TaskExecuted.Set();
                                        }
                                    }
                                    if (m_Error != null)
                                    {
                                        m_Error(this, ex);
                                    }
                                }
                            }
                        }
                        if (!moreTasks)
                        {
                            //Wait until next task received or app is closed.
                            if (EventWaitHandle.WaitAny(new EventWaitHandle[] { info.NewTask, info.Closing }) == 1)
                            {
                                break;
                            }
                        }
                        taskinfo = null;
                        System.Diagnostics.Debug.WriteLine("Checking task: " + Guid.ToString());
                        lock (info.ClaimedTasks)
                        {
                            System.Diagnostics.Debug.WriteLine("Checking task2 : " + Guid.ToString());
                            foreach (GXClaimedTask it in info.ClaimedTasks)
                            {                                
                                if (it.Task.State == TaskState.Pending)
                                {
                                    it.Task.State = TaskState.Processing;
                                    taskinfo = it;
                                    System.Diagnostics.Debug.WriteLine("Processing task: " + it.Task.Id + " " + Guid.ToString());
                                    break;
                                }
                            }                            
                        }

                        //If task is claimed.
                        if (taskinfo != null)
                        {
                            info.TaskExecuted.Reset();
                            if (taskinfo.Task.TaskType == TaskType.MediaGetProperty)
                            {
                                IGXMedia media = null;
                                if (medias.ContainsKey(taskinfo.MediaSettings[0].Value.Key))
                                {
                                    media = medias[taskinfo.MediaSettings[0].Value.Key];
                                }
                                else
                                {
                                    media = new Gurux.Communication.GXClient().SelectMedia(taskinfo.MediaSettings[0].Key);
                                    medias.Add(taskinfo.MediaSettings[0].Value.Key, media);
                                }
                                media.Tag = taskinfo.Task;
                                Dictionary<string, object> properties = new Dictionary<string, object>();
                                foreach (string it in taskinfo.Data.Split(';'))
                                {
                                    PropertyDescriptor prop = TypeDescriptor.GetProperties(media)[it];
                                    object value = prop.GetValue(media);
                                    taskinfo.Task.State = TaskState.Succeeded;
                                    properties.Add(it, value);
                                }
                                DC.SetMediaProperties(this.Guid, taskinfo.MediaSettings[0].Key, taskinfo.MediaSettings[0].Value.Key, properties, taskinfo.Task.Id);                                
                            }
                            else if (taskinfo.Task.TaskType == TaskType.MediaSetProperty)
                            {
                                IGXMedia media = null;
                                if (medias.ContainsKey(taskinfo.MediaSettings[0].Value.Key))
                                {
                                    media = medias[taskinfo.MediaSettings[0].Value.Key];
                                }
                                else
                                {
                                    media = new Gurux.Communication.GXClient().SelectMedia(taskinfo.MediaSettings[0].Key);
                                    medias.Add(taskinfo.MediaSettings[0].Value.Key, media);
                                }
                                media.Tag = taskinfo.Task;
                                string[] tmp = taskinfo.Data.Split(new string[] {Environment.NewLine}, StringSplitOptions.None);
                                string[] names = tmp[0].Split(new char[] { ';' });
                                string[] values = tmp[1].Split(new char[] { ';' });
                                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(media);
                                for (int pos = 0; pos != names.Length; ++pos)
                                {
                                    PropertyDescriptor prop = properties[names[pos]];
                                    object value;
                                    if (prop.PropertyType.IsEnum)
                                    {
                                        value = Enum.Parse(prop.PropertyType, values[pos]);
                                    }
                                    else
                                    {
                                        value = Convert.ChangeType(values[pos], prop.PropertyType);
                                    }
                                    prop.SetValue(media, value);
                                }
                                taskinfo.Task.State = TaskState.Succeeded;                                
                            }
                            else if (taskinfo.Task.TaskType == TaskType.MediaOpen)
                            {
                                IGXMedia media = null;
                                leaveConnectionOpen = true;
                                if (medias.ContainsKey(taskinfo.MediaSettings[0].Value.Key))
                                {
                                    media = medias[taskinfo.MediaSettings[0].Value.Key];
                                    media.Tag = taskinfo.Task;
                                    try
                                    {
                                        if (media.IsOpen)
                                        {
                                            media_OnMediaStateChange(media, new MediaStateEventArgs(MediaState.Open));
                                        }
                                        else
                                        {
                                            if (TraceLevel != System.Diagnostics.TraceLevel.Off)
                                            {
                                                media.Trace = TraceLevel;
                                                media.OnTrace += new TraceEventHandler(media_OnTrace);
                                            }
                                            media.Settings = taskinfo.MediaSettings[0].Value.Value;
                                            media.OnReceived += new ReceivedEventHandler(media_OnReceived);
                                            media.OnMediaStateChange += new MediaStateChangeEventHandler(media_OnMediaStateChange);
                                            media.OnError += new Gurux.Common.ErrorEventHandler(media_OnError);
                                            media.Open();
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        if (media != null)
                                        {
                                            if (TraceLevel != System.Diagnostics.TraceLevel.Off)
                                            {
                                                media.OnTrace -= new TraceEventHandler(media_OnTrace);
                                            }
                                            media.OnReceived -= new ReceivedEventHandler(media_OnReceived);
                                            media.OnMediaStateChange -= new MediaStateChangeEventHandler(media_OnMediaStateChange);
                                            media.OnError -= new Gurux.Common.ErrorEventHandler(media_OnError);
                                        }
                                        throw ex;
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        media = new Gurux.Communication.GXClient().SelectMedia(taskinfo.MediaSettings[0].Key);
                                        media.Tag = taskinfo.Task;
                                        if (TraceLevel != System.Diagnostics.TraceLevel.Off)
                                        {
                                            media.Trace = TraceLevel;
                                            media.OnTrace += new TraceEventHandler(media_OnTrace);
                                        }
                                        media.Settings = taskinfo.MediaSettings[0].Value.Value;
                                        media.OnReceived += new ReceivedEventHandler(media_OnReceived);
                                        media.OnMediaStateChange += new MediaStateChangeEventHandler(media_OnMediaStateChange);
                                        media.OnError += new Gurux.Common.ErrorEventHandler(media_OnError);
                                        media.Open();
                                        medias.Add(taskinfo.MediaSettings[0].Value.Key, media);
                                    }
                                    catch (Exception ex)
                                    {
                                        if (media != null)
                                        {
                                            if (TraceLevel != System.Diagnostics.TraceLevel.Off)
                                            {
                                                media.OnTrace -= new TraceEventHandler(media_OnTrace);
                                            }
                                            media.OnReceived -= new ReceivedEventHandler(media_OnReceived);
                                            media.OnMediaStateChange -= new MediaStateChangeEventHandler(media_OnMediaStateChange);
                                            media.OnError -= new Gurux.Common.ErrorEventHandler(media_OnError);
                                        }
                                        throw ex;
                                    }
                                }
                                taskinfo.Task.State = TaskState.Succeeded;                                
                            }
                            else if (taskinfo.Task.TaskType == TaskType.MediaClose)
                            {
                                if (medias.ContainsKey(taskinfo.MediaSettings[0].Value.Key))
                                {
                                    IGXMedia media = medias[taskinfo.MediaSettings[0].Value.Key];
                                    media.Tag = taskinfo.Task;
                                    medias.Remove(taskinfo.MediaSettings[0].Value.Key);
                                    media.Close();
                                    media.OnMediaStateChange -= new MediaStateChangeEventHandler(media_OnMediaStateChange);
                                    media.OnError -= new Gurux.Common.ErrorEventHandler(media_OnError);
                                    media.OnReceived -= new ReceivedEventHandler(media_OnReceived);
                                    if (TraceLevel != System.Diagnostics.TraceLevel.Off)
                                    {                                     
                                        media.OnTrace -= new TraceEventHandler(media_OnTrace);
                                    }
                                }
                                leaveConnectionOpen = false;
                                taskinfo.Task.State = TaskState.Succeeded;                                
                            }
                            else if (taskinfo.Task.TaskType == TaskType.MediaWrite)
                            {
                                IGXMedia media;
                                if (!medias.ContainsKey(taskinfo.MediaSettings[0].Value.Key))
                                {                                    
                                    media = new Gurux.Communication.GXClient().SelectMedia(taskinfo.MediaSettings[0].Key);
                                    media.Tag = taskinfo.Task;
                                    medias.Add(taskinfo.MediaSettings[0].Value.Key, media);
                                    media.Settings = taskinfo.MediaSettings[0].Value.Value;
                                    media.OnReceived += new ReceivedEventHandler(media_OnReceived);
                                    media.OnMediaStateChange += new MediaStateChangeEventHandler(media_OnMediaStateChange);
                                    media.OnError += new Gurux.Common.ErrorEventHandler(media_OnError);
                                    media.Open();
                                }
                                else
                                {
                                    media = medias[taskinfo.MediaSettings[0].Value.Key];
                                    media.Tag = taskinfo.Task;
                                }
                                media.Send(Gurux.Common.GXCommon.HexToBytes(taskinfo.Data, false), null);
                                taskinfo.Task.State = TaskState.Succeeded;                                
                            }
                            else if (taskinfo.Task.TaskType == TaskType.MediaState ||
                                taskinfo.Task.TaskType == TaskType.MediaError)
                            {
                                //This might happend is DC is closed and there are event info left.
                                taskinfo.Task.State = TaskState.Succeeded;                                
                            }
                            else
                            {
                                HandleDevice(info, pc, ref path, ref leaveConnectionOpen, taskinfo);
                            }
                            info.TaskExecuted.Set();
                        }
                    }
                }
                catch (Exception ex)
                {
                    lock (info.Exceptions)
                    {
                        //Taskinfo is null in disconnecting.
                        if (taskinfo != null)
                        {
                            //Mikko task voidaan ajaa useampaan kertaan esim schedule jolloin taskinfo voi jo olla.
                            info.Exceptions.Add(taskinfo, ex);
                            taskinfo.Task.State = TaskState.Failed;
                            info.TaskExecuted.Set();
                        }
                    }
                    if (m_Error != null)
                    {
                        m_Error(this, ex);
                    }
                }
            }
            try
            {
                pc.Close();
            }
            catch (System.Runtime.Remoting.RemotingException)
            {

            }
            //Unload app domain.
            System.AppDomain.Unload(td);
        }