/*
  ==============================================================================

   This file is part of the JUCE library - "Jules' Utility Class Extensions"
   Copyright 2004-6 by Raw Material Software ltd.

  ------------------------------------------------------------------------------

   JUCE can be redistributed and/or modified under the terms of the
   GNU General Public License, as published by the Free Software Foundation;
   either version 2 of the License, or (at your option) any later version.

   JUCE is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with JUCE; if not, visit www.gnu.org/licenses or write to the
   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
   Boston, MA 02111-1307 USA

  ------------------------------------------------------------------------------

   If you'd like to release a closed-source product which uses JUCE, commercial
   licenses are also available: visit www.rawmaterialsoftware.com/juce for
   more information.

  ==============================================================================
*/

#include "../../../../juce_core/basics/juce_StandardHeader.h"

BEGIN_JUCE_NAMESPACE

#include "juce_KeyPress.h"
#include "../juce_Component.h"


//==============================================================================
KeyPress::KeyPress() throw()
    : keyCode (0),
      mods (0)
{
}

KeyPress::KeyPress (const int keyCode_,
                    const ModifierKeys& mods_) throw()
    : keyCode (keyCode_),
      mods (mods_)
{
}

KeyPress::KeyPress (const KeyPress& other) throw()
    : keyCode (other.keyCode),
      mods (other.mods)
{
}

const KeyPress& KeyPress::operator= (const KeyPress& other) throw()
{
    keyCode = other.keyCode;
    mods = other.mods;

    return *this;
}

bool KeyPress::operator== (const KeyPress& other) const throw()
{
    return mods.getRawFlags() == other.mods.getRawFlags()
            && (keyCode == other.keyCode
                 || (keyCode < 256
                      && other.keyCode < 256
                      && String::toLowerCase ((tchar) keyCode)
                           == String::toLowerCase ((tchar) other.keyCode)));
}

bool KeyPress::operator!= (const KeyPress& other) const throw()
{
    return ! operator== (other);
}

bool KeyPress::isCurrentlyDown() const
{
    return isKeyCurrentlyDown (keyCode)
            && ((ModifierKeys::getCurrentModifiers().getRawFlags()
                   & (ModifierKeys::commandModifier | ModifierKeys::ctrlModifier | ModifierKeys::altModifier))
                  == mods.getRawFlags());
}

//==============================================================================
static const tchar* spaceBarName        = T("spacebar");
static const tchar* returnKeyName       = T("return");
static const tchar* escapeKeyName       = T("escape");
static const tchar* backspaceKeyName    = T("backspace");
static const tchar* leftKeyName         = T("cursor left");
static const tchar* rightKeyName        = T("cursor right");
static const tchar* upKeyName           = T("cursor up");
static const tchar* downKeyName         = T("cursor down");
static const tchar* pageUpKeyName       = T("page up");
static const tchar* pageDownKeyName     = T("page down");
static const tchar* homeKeyName         = T("home");
static const tchar* endKeyName          = T("end");
static const tchar* deleteKeyName       = T("delete");
static const tchar* insertKeyName       = T("insert");
static const tchar* tabKeyName          = T("tab");
static const tchar* playKeyName         = T("play");
static const tchar* stopKeyName         = T("stop");
static const tchar* fastForwardKeyName  = T("fast forward");
static const tchar* rewindKeyName       = T("rewind");

const KeyPress KeyPress::createFromDescription (const String& desc)
{
    int modifiers = 0;

    if (desc.containsWholeWordIgnoreCase (T("ctrl"))
         || desc.containsWholeWordIgnoreCase (T("control"))
         || desc.containsWholeWordIgnoreCase (T("ctl")))
        modifiers |= ModifierKeys::ctrlModifier;

    if (desc.containsWholeWordIgnoreCase (T("shift"))
         || desc.containsWholeWordIgnoreCase (T("shft")))
        modifiers |= ModifierKeys::shiftModifier;

    if (desc.containsWholeWordIgnoreCase (T("alt"))
         || desc.containsWholeWordIgnoreCase (T("option")))
        modifiers |= ModifierKeys::altModifier;

    if (desc.containsWholeWordIgnoreCase (T("command"))
         || desc.containsWholeWordIgnoreCase (T("cmd")))
        modifiers |= ModifierKeys::commandModifier;

    int key = 0;

    if (desc.containsWholeWordIgnoreCase (spaceBarName))
        key = spaceKey;
    else if (desc.containsWholeWordIgnoreCase (returnKeyName))
        key = returnKey;
    else if (desc.containsWholeWordIgnoreCase (escapeKeyName))
        key = escapeKey;
    else if (desc.containsWholeWordIgnoreCase (backspaceKeyName))
        key = backspaceKey;
    else if (desc.containsWholeWordIgnoreCase (pageUpKeyName))
        key = pageUpKey;
    else if (desc.containsWholeWordIgnoreCase (pageDownKeyName))
        key = pageDownKey;
    else if (desc.containsWholeWordIgnoreCase (leftKeyName))
        key = leftKey;
    else if (desc.containsWholeWordIgnoreCase (rightKeyName))
        key = rightKey;
    else if (desc.containsWholeWordIgnoreCase (upKeyName))
        key = upKey;
    else if (desc.containsWholeWordIgnoreCase (downKeyName))
        key = downKey;
    else if (desc.containsWholeWordIgnoreCase (homeKeyName))
        key = homeKey;
    else if (desc.containsWholeWordIgnoreCase (endKeyName))
        key = endKey;
    else if (desc.containsWholeWordIgnoreCase (deleteKeyName))
        key = deleteKey;
    else if (desc.containsWholeWordIgnoreCase (insertKeyName))
        key = insertKey;
    else if (desc.containsWholeWordIgnoreCase (tabKeyName))
        key = tabKey;
    else if (desc.containsWholeWordIgnoreCase (playKeyName))
        key = playKey;
    else if (desc.containsWholeWordIgnoreCase (stopKeyName))
        key = stopKey;
    else if (desc.containsWholeWordIgnoreCase (fastForwardKeyName))
        key = fastForwardKey;
    else if (desc.containsWholeWordIgnoreCase (rewindKeyName))
        key = rewindKey;
    else
    {
        for (int i = 1; i <= 12; ++i)
            if (desc.containsWholeWordIgnoreCase (T("f") + String (i)))
                key = F1Key + i - 1;
    }

    if (key == 0)
    {
        const int hexCode = desc.fromFirstOccurrenceOf (T("#"), false, false)
                                .toLowerCase()
                                .retainCharacters (T("0123456789abcdef"))
                                .getHexValue32();

        if (hexCode > 0)
        {
            key = hexCode;
        }
        else
        {
            key = String::toUpperCase (desc.getLastCharacter());
        }
    }

    return KeyPress (key, ModifierKeys (modifiers));
}

const String KeyPress::getTextDescription() const
{
    String desc;

    if (keyCode > 0)
    {
        if (mods.isCtrlDown())
            desc += T("ctrl + ");

        if (mods.isShiftDown())
            desc += T("shift + ");

#ifdef JUCE_MAC
          // only do this on the mac, because on Windows ctrl and command are the same,
          // and this would get confusing
          if (mods.isCommandDown())
              desc += T("command + ");

        if (mods.isAltDown())
            desc += T("option + ");
#else
        if (mods.isAltDown())
            desc += T("alt + ");
#endif

        if (keyCode == escapeKey)
            desc += escapeKeyName;
        else if (keyCode == spaceKey)
            desc += spaceBarName;
        else if (keyCode == returnKey)
            desc += returnKeyName;
        else if (keyCode == backspaceKey)
            desc += backspaceKeyName;
        else if (keyCode == deleteKey)
            desc += deleteKeyName;
        else if (keyCode == insertKey)
            desc += insertKeyName;
        else if (keyCode == leftKey)
            desc += leftKeyName;
        else if (keyCode == rightKey)
            desc += rightKeyName;
        else if (keyCode == upKey)
            desc += upKeyName;
        else if (keyCode == downKey)
            desc += downKeyName;
        else if (keyCode == pageUpKey)
            desc += pageUpKeyName;
        else if (keyCode == pageDownKey)
            desc += pageDownKeyName;
        else if (keyCode == homeKey)
            desc += homeKeyName;
        else if (keyCode == endKey)
            desc += endKeyName;
        else if (keyCode == tabKey)
            desc += tabKeyName;
        else if (keyCode >= F1Key && keyCode <= F12Key)
            desc << T("F") << (1 + keyCode - F1Key);
        else if (keyCode == playKey)
            desc += playKeyName;
        else if (keyCode == stopKey)
            desc += stopKeyName;
        else if (keyCode == fastForwardKey)
            desc += fastForwardKeyName;
        else if (keyCode == rewindKey)
            desc += rewindKeyName;
        else if (keyCode >= 33 && keyCode < 176)
            desc += String::toUpperCase ((tchar) keyCode);
        else
            desc << T('#') << String::toHexString (keyCode);
    }

    return desc;
}

END_JUCE_NAMESPACE
