/// <summary>
    /// 
    /// </summary>
    /// <param name="aProfileName"></param>
    /// <param name="defaults"></param>
    private void LoadMapping(string aProfileName, bool defaults)
    {
      var pathDefault = HidProfiles.GetDefaultProfilePath(aProfileName);
      var pathCustom = HidProfiles.GetCustomProfilePath(aProfileName);

      try
      {
        groupBoxLayer.Enabled = false;
        groupBoxCondition.Enabled = false;
        groupBoxAction.Enabled = false;
        treeMapping.Nodes.Clear();
        var doc = new XmlDocument();
        var path = pathDefault;
        if (!defaults && File.Exists(pathCustom))
        {
          path = pathCustom;
        }
        if (!File.Exists(path))
        {
          MessageBox.Show(
            "Can't locate mapping file " + aProfileName + "\n\nMake sure it exists in /InputDeviceMappings/defaults",
            "Mapping file missing", MessageBoxButtons.OK, MessageBoxIcon.Error);
          buttonUp.Enabled =
            buttonDown.Enabled =
              buttonNew.Enabled = buttonRemove.Enabled = buttonDefault.Enabled = buttonApply.Enabled = false;
          ShowInTaskbar = true;
          WindowState = FormWindowState.Minimized;
          var closeThread = new Thread(CloseThread);
          closeThread.Name = "InputMapperClose";
          closeThread.Start();
          return;
        }
        doc.Load(path);
        var listRemotes = doc.DocumentElement.SelectNodes("/HidHandler/HidUsageAction");

        foreach (XmlNode nodeRemote in listRemotes)
        {
          var usagePageAndCollection = nodeRemote.Attributes["UsagePage"].Value + "/" +
                                       nodeRemote.Attributes["UsageCollection"].Value;
          var remoteNode = new TreeNode(usagePageAndCollection);
          var huaAttributes = new HidUsageActionAttributes(nodeRemote.Attributes["UsagePage"].Value,
            nodeRemote.Attributes["UsageCollection"].Value,
            nodeRemote.Attributes["HandleHidEventsWhileInBackground"].Value);
          remoteNode.Tag = new NodeData("REMOTE", huaAttributes, null);
          var listButtons = nodeRemote.SelectNodes("button");
          foreach (XmlNode nodeButton in listButtons)
          {
            //Use code as name if no name attribute
            var buttonName = GetAttributeValue(nodeButton.Attributes["name"], nodeButton.Attributes["code"].Value);
            
            //Get background attribute and default to false
            var background = GetAttributeValue(nodeButton.Attributes["background"], "false");

            //Get repeat attribute and default to false
            var repeat = GetAttributeValue(nodeButton.Attributes["repeat"], "false");

            var shift = GetAttributeValue(nodeButton.Attributes["shift"], "false");
            var ctrl = GetAttributeValue(nodeButton.Attributes["ctrl"], "false");
            var alt = GetAttributeValue(nodeButton.Attributes["alt"], "false");
            var win = GetAttributeValue(nodeButton.Attributes["win"], "false");

            HidButtonAttributes hbAttributes = new HidButtonAttributes(buttonName, nodeButton.Attributes["code"].Value, background, repeat, shift, ctrl, alt, win);
            var buttonNode = new TreeNode(hbAttributes.GetText());            
            buttonNode.Tag = new NodeData("BUTTON", hbAttributes, null);
            remoteNode.Nodes.Add(buttonNode);

            var layer1Node = new TreeNode("Layer 1");
            var layer2Node = new TreeNode("Layer 2");
            var layerAllNode = new TreeNode("All Layers");
            layer1Node.Tag = new NodeData("LAYER", null, "1");
            layer2Node.Tag = new NodeData("LAYER", null, "2");
            layerAllNode.Tag = new NodeData("LAYER", null, "0");
            layer1Node.ForeColor = Color.DimGray;
            layer2Node.ForeColor = Color.DimGray;
            layerAllNode.ForeColor = Color.DimGray;

            var listActions = nodeButton.SelectNodes("action");

            foreach (XmlNode nodeAction in listActions)
            {
              var conditionString = string.Empty;
              var commandString = string.Empty;

              var condition = nodeAction.Attributes["condition"].Value.ToUpperInvariant();
              var conProperty = nodeAction.Attributes["conproperty"].Value.ToUpperInvariant();
              var command = nodeAction.Attributes["command"].Value.ToUpperInvariant();
              var cmdProperty = nodeAction.Attributes["cmdproperty"].Value.ToUpperInvariant();
              var sound = string.Empty;
              var soundAttribute = nodeAction.Attributes["sound"];
              if (soundAttribute != null)
              {
                sound = soundAttribute.Value;
              }
              var gainFocus = false;
              var focusAttribute = nodeAction.Attributes["focus"];
              if (focusAttribute != null)
              {
                gainFocus = Convert.ToBoolean(focusAttribute.Value);
              }
              var layer = Convert.ToInt32(nodeAction.Attributes["layer"].Value);

              #region Conditions

              switch (condition)
              {
                case "WINDOW":
                  conditionString =
                    GetFriendlyName(Enum.GetName(typeof (GUIWindow.Window), Convert.ToInt32(conProperty)));
                  if (string.IsNullOrEmpty(conditionString))
                  {
                    continue;
                  }
                  break;

                case "FULLSCREEN":
                  if (conProperty == "TRUE")
                  {
                    conditionString = "Fullscreen";
                  }
                  else
                  {
                    conditionString = "No Fullscreen";
                  }
                  break;

                case "PLAYER":
                  conditionString = playerList[Array.IndexOf(nativePlayerList, conProperty)];
                  break;

                case "*":
                  conditionString = "No Condition";
                  break;
              }

              #endregion Conditions

              #region Commands

              switch (command)
              {
                case "ACTION":
                  commandString = "Action \"" +
                                  GetFriendlyName(Enum.GetName(typeof (Action.ActionType), Convert.ToInt32(cmdProperty))) +
                                  "\"";
                  break;

                case "KEY":
                  commandString = "Key \"" + cmdProperty + "\"";
                  break;

                case "WINDOW":
                  commandString = "Window \"" +
                                  GetFriendlyName(Enum.GetName(typeof (GUIWindow.Window), Convert.ToInt32(cmdProperty))) +
                                  "\"";
                  break;

                case "TOGGLE":
                  commandString = "Toggle Layer";
                  break;

                case "POWER":
                  commandString = powerList[Array.IndexOf(nativePowerList, cmdProperty)];
                  break;

                case "PROCESS":
                  commandString = processList[Array.IndexOf(nativeProcessList, cmdProperty)];
                  break;
              }

              #endregion Commands

              var conditionNode = new TreeNode(conditionString);
              conditionNode.Tag = new NodeData("CONDITION", condition, conProperty);
              if (commandString == "Action \"Key Pressed\"")
              {
                var cmdKeyChar = nodeAction.Attributes["cmdkeychar"].Value;
                var cmdKeyCode = nodeAction.Attributes["cmdkeycode"].Value;
                var commandNode = new TreeNode(string.Format("Key Pressed: {0} [{1}]", cmdKeyChar, cmdKeyCode));

                var key = new Key(Convert.ToInt32(cmdKeyChar), Convert.ToInt32(cmdKeyCode));

                commandNode.Tag = new NodeData("COMMAND", "KEY", key, gainFocus);
                commandNode.ForeColor = Color.DarkGreen;
                conditionNode.ForeColor = Color.Blue;
                conditionNode.Nodes.Add(commandNode);
              }
              else
              {
                var commandNode = new TreeNode(commandString);
                commandNode.Tag = new NodeData("COMMAND", command, cmdProperty, gainFocus);
                commandNode.ForeColor = Color.DarkGreen;
                conditionNode.ForeColor = Color.Blue;
                conditionNode.Nodes.Add(commandNode);
              }

              var soundNode = new TreeNode(sound);
              soundNode.Tag = new NodeData("SOUND", null, sound);
              if (sound == string.Empty)
              {
                soundNode.Text = "No Sound";
              }
              soundNode.ForeColor = Color.DarkRed;
              conditionNode.Nodes.Add(soundNode);

              if (layer == 1)
              {
                layer1Node.Nodes.Add(conditionNode);
              }
              if (layer == 2)
              {
                layer2Node.Nodes.Add(conditionNode);
              }
              if (layer == 0)
              {
                layerAllNode.Nodes.Add(conditionNode);
              }
            }
            if (layer1Node.Nodes.Count > 0)
            {
              buttonNode.Nodes.Add(layer1Node);
            }
            if (layer2Node.Nodes.Count > 0)
            {
              buttonNode.Nodes.Add(layer2Node);
            }
            if (layerAllNode.Nodes.Count > 0)
            {
              buttonNode.Nodes.Add(layerAllNode);
            }
          }
          treeMapping.Nodes.Add(remoteNode);
          if (listRemotes.Count == 1)
          {
            remoteNode.Expand();
          }
        }
        changedSettings = false;
      }
      catch (Exception ex)
      {
        Log.Error(ex);
        //Force loading defaults if we were not already doing it
        if (!defaults)
        {
          //Possibly corrupted custom configuration
          //Try loading the defaults then
          LoadMapping("classic", true);
        }
        else
        {
          //Loading the default configuration failed
          //Just propagate our exception then
          throw ex;
        }        
      }
    }
    private void buttonNew_Click(object sender, EventArgs e)
    {
      var node = treeMapping.SelectedNode;
      var data = (NodeData) node.Tag;

      var newLayer = new TreeNode("All Layers");
      newLayer.Tag = new NodeData("LAYER", null, "0");
      newLayer.ForeColor = Color.DimGray;

      var newCondition = new TreeNode("No Condition");
      newCondition.Tag = new NodeData("CONDITION", "*", "-1");
      newCondition.ForeColor = Color.Blue;

      var newCommand = new TreeNode("Action \"Select Item\"");
      newCommand.Tag = new NodeData("COMMAND", "ACTION", "7");
      newCommand.ForeColor = Color.DarkGreen;

      var newSound = new TreeNode("No Sound");
      newSound.Tag = new NodeData("SOUND", string.Empty, string.Empty);
      newSound.ForeColor = Color.DarkRed;

      HidButtonAttributes newButtonAttributes = new HidButtonAttributes(Keys.A.ToString(), Keys.A.ToString(), false.ToString(), false.ToString(), false.ToString(), false.ToString(), false.ToString(), false.ToString());
      var newButtonNode = new TreeNode(newButtonAttributes.GetText());
      newButtonNode.Tag = new NodeData("BUTTON", newButtonAttributes, null);

      switch (data.Type)
      {
        case "REMOTE":
        {
          //Check that the selected "remote" is a keyboard
          HidUsageActionAttributes remoteAttributes = (HidUsageActionAttributes) data.Parameter;
          if (remoteAttributes.UsagePage.Equals(SharpLib.Hid.UsagePage.GenericDesktopControls.ToString()) &&
              remoteAttributes.UsageCollection.Equals(SharpLib.Hid.UsageCollection.GenericDesktop.Keyboard.ToString()))
          {
            //We support adding new buttons to keyboards
            newCondition.Nodes.Add(newCommand);
            newCondition.Nodes.Add(newSound);
            newLayer.Nodes.Add(newCondition);
            newButtonNode.Nodes.Add(newLayer);
            node.Nodes.Add(newButtonNode);
            newButtonNode.ExpandAll();
            treeMapping.SelectedNode = newButtonNode;
          }
        }
          break;
        case "LAYER":
          newCondition.Nodes.Add(newCommand);
          newCondition.Nodes.Add(newSound);
          newLayer.Nodes.Add(newCondition);
          node.Parent.Nodes.Add(newLayer);
          newLayer.Expand();
          treeMapping.SelectedNode = newLayer;
          break;

        case "CONDITION":
          newCondition.Nodes.Add(newCommand);
          newCondition.Nodes.Add(newSound);
          node.Parent.Nodes.Add(newCondition);
          newCondition.Expand();
          treeMapping.SelectedNode = newCondition;
          break;

        case "COMMAND":
        case "SOUND":
          newCondition.Nodes.Add(newCommand);
          newCondition.Nodes.Add(newSound);
          node.Parent.Parent.Nodes.Add(newCondition);
          newCondition.Expand();
          treeMapping.SelectedNode = newCondition;
          break;

        case "BUTTON":
          newCondition.Nodes.Add(newCommand);
          newCondition.Nodes.Add(newSound);
          newLayer.Nodes.Add(newCondition);
          node.Nodes.Add(newLayer);
          newLayer.Expand();
          treeMapping.SelectedNode = newLayer;
          break;

        default:
          //NewButtonForm newButtonForm = new NewButtonForm();
          //newButtonForm.ShowDialog();
          //if (newButtonForm.Accepted)
          //{
          //  Log.Info("Name: {0}", newButtonForm.ButtonName);
          //  Log.Info("Code: {0}", newButtonForm.ButtonCode);
          //}
          break;
      }
      changedSettings = true;

      treeMapping_AfterSelect(this, new TreeViewEventArgs(treeMapping.SelectedNode, TreeViewAction.ByKeyboard));
    }