/// <summary>
        /// Loads character state from a stream
        /// </summary>
        /// <param name="s"></param>
        public void LoadCharacterFromStream(Stream s, Boolean autoLoadResources = false)
        {
            try
            {
                // Load XMLDocument
                XmlDocument doc = new XmlDocument();
                s.Position = 0;
                doc.Load(s);

                // Get Character Name and Verify it
                String name = doc.SelectSingleNode("MoltenMercuryState").Attributes["name"].InnerText;
                if (name != resourceManager.Name)
                {
                    if (autoLoadResources && characters.ContainsKey(name))
                    {
                        LoadCharacterResourcesGeneric(characters[name]);
                    }
                    else
                    {
                        MessageBox.Show(String.Format(Localization.LocalizationDictionary.Instance["ERR_701"], name));
                        return;
                    }
                }

                // Clear current selection and layer adjustment data
                resourceManager.ClearSelection();
                ClearLayerAdjustments();

                // Load Selection
                foreach (XmlNode selNode in doc.SelectNodes("MoltenMercuryState/Selection"))
                {
                    String groupName = selNode.Attributes["group"].InnerText;
                    String setName = selNode.Attributes["set"].InnerText;

                    CharaSetGroup cgroup = resourceManager.GetGroupByName(groupName);
                    if (cgroup == null)
                        throw new Exception(String.Format("CharaSetGroup {0} Not Found!", groupName));
                    CharaSet cset = cgroup.GetSetByName(setName);
                    if (cset == null)
                        throw new Exception(String.Format("CharaSet {0} Not Found!", setName));

                    if (cgroup.Multiselect)
                    {
                        Int32 ladj = Int32.Parse(selNode.Attributes["adjustment"].InnerText);
                        cset.LayerAdjustment = ladj;
                    }

                    cset.Selected = true;
                }

                // Regenerate layer adjustment values
                foreach (CharaSetGroup csg in resourceManager)
                {
                    if (csg.Multiselect)
                        GenerateLayerAdjustments(csg);
                }

                resourceManager.Processors.Clear();
                UpdateColorProcessorList();

                // Load Color Presets
                foreach (XmlNode colNode in doc.SelectNodes("MoltenMercuryState/ImageProcessor"))
                {
                    String group = colNode.Attributes["colorgroup"].InnerText;
                    String preset = colNode.InnerText;

                    if (resourceManager.Processors.ContainsKey(group))
                        resourceManager.Processors[group].DecodeSettings(preset);
                }

                tmpProcessor = (ImageProcessor)resourceManager.Processors[cmbColorProcessors.Text].Clone();
                SyncTmpToUI();

                // Reflect changes on UI
                using (CharaBlocker cb = new CharaBlocker(this))
                {
                    ReloadPropertyListView((CharaSetGroup)cmbCharaProp.SelectedItem);
                    cb.DummyMethod();
                }

            }
            catch
            {


                // Done, Delete all cached data and Update Stuff
                UpdateCharacterPreviewAsync();
            }
        }
        public void UpdateColorProcessorList()
        {
            using (CharaBlocker cb = new CharaBlocker(this))
            {
                resourceManager.UpdateColorProcessorList();

                // Update UI controls to reflect changes
                cmbColorProcessors.BeginUpdate();
                cmbColorProcessors.Items.Clear();
                cmbColorProcessors.Items.AddRange(resourceManager.Processors.Keys.ToArray());
                if (cmbColorProcessors.Items.Count > 0)
                    cmbColorProcessors.SelectedIndex = 0;
                cmbColorProcessors.EndUpdate();

                cb.DummyMethod();
            }
        }
        /// <summary>
        /// Loads character resources from another application whose 
        /// data formats are supported by this one.
        /// </summary>
        /// <param name="path"></param>
        public void LoadCharacterResourcesInterop(String path)
        {
            Boolean hasState = true;
            using (CharaBlocker cb = new CharaBlocker(this))
            {

                // Load Resources and reflect them on UI
                Interop.CharaxDirHelper interopHelper = new Interop.CharaxDirHelper(path);
                using (MemoryStream tmp = new MemoryStream())
                {
                    interopHelper.GenerateDescriptor(tmp);
                    tmp.Position = 0;
                    resourceManager = CharacterResourceManager.FromXML(tmp);
                }

                // Set up bitmap loader with root at path dir
                resourceManager.FileSystemProxy = new DefaultFileSystemProxy(Path.GetDirectoryName(path));

                ReloadResourceManager();
                ResetSelection();
                UpdateColorProcessorList();
                cmbColorProcessors.SelectedIndex = 0;

                // If there is a saved state, restore it as well
                // Here we usa a FileSystemProxy because we have no idea whether
                // the state is stored on a file or a package
                Stream state = resourceManager.FileSystemProxy.GetSavedStateStream();
                if (state != null)
                {
                    LoadCharacterFromStream(state, false);
                    state.Dispose();
                }
                else
                {
                    ResetSelection();
                    resourceManager.Processors.Clear();
                    UpdateColorProcessorList();

                    hasState = false;
                }

                // Reflect color processors on the UI
                UpdateColorProcessorList();

                // Reload Chara Set List
                ReloadPropertyListView((CharaSetGroup)cmbCharaProp.SelectedItem);

                // Generate Layer Adjustment values
                foreach (CharaSetGroup csg in resourceManager)
                {
                    if (!csg.Multiselect) continue;
                    GenerateLayerAdjustments(csg);
                }

                // Maintain CharaBlocker instance
                cb.DummyMethod();

            }
            miTools.Enabled = false;
            if (!hasState) UpdateCharacterPreviewAsync();
            DebugHelper.DebugPrint("Successfully loaded Legacy: {0}", resourceManager.Name);
        }
        /// <summary>
        /// Loads a character packed into AFS file
        /// File extension doesn't have to be AFS
        /// </summary>
        /// <param name="path"></param>
        public void LoadCharacterResourcesAFS(String path)
        {
            using (CharaBlocker cb = new CharaBlocker(this))
            {
                AFSFileSystemProxy proxy = new AFSFileSystemProxy(path);

                using (ExStream descriptor = new ExStream())
                {
                    PackageEntry entry = proxy.Archive.TryGetEntry("character.mcres");
                    proxy.Archive.Extract(entry, descriptor);
                    descriptor.Position = 0;

                    resourceManager = CharacterResourceManager.FromXML(descriptor);
                }

                resourceManager.FileSystemProxy = proxy;
                resourceManager.AllowChange = proxy.Archive.TryGetEntry(".lock") == null;


                ReloadResourceManager();
                ResetSelection();
                UpdateColorProcessorList();
                cmbColorProcessors.SelectedIndex = 0;

                // If there is a saved state, restore it as well
                // Here we usa a FileSystemProxy because we have no idea whether
                // the state is stored on a file or a package
                Stream state = resourceManager.FileSystemProxy.GetSavedStateStream();
                if (state != null)
                {
                    LoadCharacterFromStream(state, false);
                    state.Dispose();
                }
                else
                {
                    ResetSelection();
                    resourceManager.Processors.Clear();
                    UpdateColorProcessorList();
                }

                // Reflect color processors on the UI
                UpdateColorProcessorList();

                // Reload Chara Set List
                ReloadPropertyListView((CharaSetGroup)cmbCharaProp.SelectedItem);

                // Generate Layer Adjustment values
                foreach (CharaSetGroup csg in resourceManager)
                {
                    if (!csg.Multiselect) continue;
                    GenerateLayerAdjustments(csg);
                }

                // Maintain CharaBlocker instance
                cb.DummyMethod();
                
            }

            miTools.Enabled = false;
            UpdateCharacterPreviewAsync();
            DebugHelper.DebugPrint("Successfully loaded AFS: {0}", resourceManager.Name);
        }
        /// <summary>
        /// Loads character resources from an XML file
        /// </summary>
        /// <param name="path">Path to the extension</param>
        public void LoadCharacterResourcesRaw(String path)
        {
            using (CharaBlocker cb = new CharaBlocker(this))
            {

                // Load Resources and reflect them on UI
                resourceManager = CharacterResourceManager.FromXML(path);
                // Set up bitmap loader with root at path dir
                resourceManager.FileSystemProxy = new DefaultFileSystemProxy(Path.GetDirectoryName(path));
                // Update UI
                ReloadResourceManager();

                // Reinitialize selection buffer
                ResetSelection();

                // Reflect color processors on the UI
                UpdateColorProcessorList();
                cmbColorProcessors.SelectedIndex = 0;

                // If there is a saved state, restore it as well
                // Here we usa a FileSystemProxy because we have no idea whether
                // the state is stored on a file or a package
                Stream state = resourceManager.FileSystemProxy.GetSavedStateStream();
                if (state != null)
                {
                    LoadCharacterFromStream(state, false);
                    state.Dispose();
                }

                // Generate Layer Adjustment values
                foreach (CharaSetGroup csg in resourceManager)
                {
                    if (!csg.Multiselect) continue;
                    GenerateLayerAdjustments(csg);
                }

                // Enable tool menu
                miTools.Enabled = File.Exists(Path.Combine(Application.StartupPath, "mcu.exe"));

                // Maintain CharaBlocker instance
                cb.DummyMethod();
            }

            DebugHelper.DebugPrint("Successfully loaded MCRES: {0}", resourceManager.Name);
        }
        void ReloadPropertyListView(CharaSetGroup setg)
        {
            using (CharaBlocker cb = new CharaBlocker(this))
            {
                lvCharaSets.BeginUpdate();
                // Get Group ID
                Int32 gid = cmbCharaProp.SelectedIndex;
                if (gid < 0)
                {
                    lvCharaSets.EndUpdate();
                    return;
                }

                // Clear property options
                lvCharaSets.Items.Clear();

                // If no CharaSetGroup selected, there is no need to continue reloading
                if (setg == null)
                {
                    lvCharaSets.EndUpdate();
                    return;
                }

                // Start updating listview
                List<CharaSet> orderedItems = new List<CharaSet>();
                orderedItems.AddRange(setg);
                if (setg.Multiselect)
                    orderedItems.Sort(new Comparison<CharaSet>(
                        (CharaSet a, CharaSet b) => { return b.LayerAdjustment.CompareTo(a.LayerAdjustment); }));
                
                foreach (CharaSet cset in orderedItems)
                    lvCharaSets.Items.Add(new CharaSetListViewItemAdapter(cset));
                
                lvCharaSets.EndUpdate();
                cb.DummyMethod();
            }

            DebugHelper.DebugPrint("UI Reloaded for {0}", setg.Name);
        }
        public void SyncTmpToUI()
        {
            using (CharaBlocker cb = new CharaBlocker(this))
            {
                chkColorHideSelection.Checked = tmpProcessor.AA == 0;
                lblColorBase.BackColor = tmpProcessor.BaseColor;
                cmbColorHM.SelectedIndex = (int)tmpProcessor.HueMode;
                cmbColorSM.SelectedIndex = (int)tmpProcessor.SaturationMode;
                cmbColorLM.SelectedIndex = (int)tmpProcessor.LightnessMode;

                tbColorHA.Value = (int)(tmpProcessor.HA * tbColorHA.Maximum);
                tbColorSA.Value = (int)(tmpProcessor.SA * (tbColorSA.Maximum / 2));
                tbColorLA.Value = (int)(tmpProcessor.LA * (tbColorLA.Maximum / 2));
                tbColorStep.Value = (int)(tmpProcessor.Step * tbColorStep.Maximum);

                txtImProcInfo.Text = tmpProcessor.ToString();
            }
        }