using System ;
using System.Text ;
using System.Security ;
using System.Collections.Generic ;
using System.Windows.Forms ;

using log4net ;

// --------------------------------------------------------------------

public abstract class Shortcut
{

    private static Dictionary<Keys,Shortcut> mRegisteredShortcuts = new Dictionary<Keys,Shortcut>() ;

    private Keys mKeys ;

    public Shortcut( Keys keys )
    {
        // initialize
        mKeys = keys ;
    }

    public static Keys? parseShortcutString( string val )
    {
        // parse the shortcut
        // FUDGE! We can't just pass in '-' since a Mono-compiled EXE has trouble running on Windows :-/
        string[] parts = val.ToLower().Split( new char[]{'-'} ) ;
        if ( parts.Length <= 1 )
            return null ;
        Keys keys ;
        bool rc = Enum.TryParse( parts[parts.Length-1], true, out keys ) ;
        if ( ! rc )
            return null ;
        for ( int i=0 ; i < parts.Length-1 ; ++i ) {
            if ( parts[i] == "ctrl" )
                keys |= Keys.Control ;
            else if ( parts[i] == "alt" )
                keys |= Keys.Alt ;
            else if ( parts[i] == "shift" )
                keys |= Keys.Shift ;
            else
                return null ;
        }
        return keys ;
    }

    public static bool handleShortcut( Keys keys )
    {
        // look for a registered shortcut
        Shortcut shortcut = findRegisteredShortcut( keys ) ;
        if ( shortcut == null )
            return false ;

        // found one - execute it
        ILog logger = LogManager.GetLogger( "shortcuts" ) ;
        logger.Info( $"Executing shortcut: {shortcut}" ) ;
        shortcut.executeShortcut() ;
        return true ;
    }

    public static void registerShortcut( Shortcut shortcut )
    {
        // register the shortcut
        if ( findRegisteredShortcut( shortcut.mKeys ) != null ) {
            Program.logStartupMsg( "bad-shortcut", $"Found duplicate: {shortcut}" ) ;
        }
        mRegisteredShortcuts[ shortcut.mKeys ] = shortcut ;
    }

    public static Shortcut findRegisteredShortcut( Keys keys )
    {
        // look for a registered shortcut
        Shortcut shortcut ;
        if ( ! mRegisteredShortcuts.TryGetValue( keys, out shortcut ) )
            return null ;
        return shortcut ;
    }

    public static Dictionary< Type, List<Shortcut> > getRegisteredShortcuts()
    {
        // return the registered shortcuts (grouped by type)
        Dictionary<Type,List<Shortcut>> shortcuts = new Dictionary<Type,List<Shortcut>>() ;
        foreach( Shortcut shortcut in mRegisteredShortcuts.Values ) {
            Type shortcutType = shortcut.GetType() ;
            List<Shortcut> shortcutList ;
            if ( ! shortcuts.TryGetValue( shortcutType, out shortcutList ) )
                shortcuts[shortcutType] = shortcutList = new List<Shortcut>() ;
            shortcutList.Add( shortcut ) ;
        }

        return shortcuts ;
    }

    public override string ToString()
    {
        // return the Shortcut as a string
        StringBuilder buf = new StringBuilder() ;
        if ( (mKeys & Keys.Control) != 0 )
            buf.Append( "Ctrl-" ) ;
        if ( (mKeys & Keys.Shift) != 0 )
            buf.Append( "Shift-" ) ;
        if ( (mKeys & Keys.Alt) != 0 )
            buf.Append( "Alt-" ) ;
        buf.Append( getKeyCode() ) ;
        return buf.ToString() ;
    }

    public Keys getKeyCode() { return mKeys & ~(Keys.Control | Keys.Shift | Keys.Alt) ; }

    public int countModifiers()
    {
        // count how many modifiers the shortcut has
        int nModifiers = 0 ;
        if ( (mKeys & Keys.Control) != 0 )
            ++ nModifiers ;
        if ( (mKeys & Keys.Shift) != 0 )
            ++ nModifiers ;
        if ( (mKeys & Keys.Alt) != 0 )
            ++ nModifiers ;
        return nModifiers ;
    }

    public abstract void executeShortcut() ;
    public abstract string textDescription() ;
    public abstract string htmlDescription() ;

}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

public class ChartImageShortcut : Shortcut
{
    private List<ChartImage> mChartImages = new List<ChartImage>() ;

    public ChartImageShortcut( Keys keys ) : base( keys ) { }

    public override void executeShortcut()
    {
        // execute the shortcut
        ILog logger = LogManager.GetLogger( "shortcuts" ) ;
        foreach ( ChartImage chartImage in mChartImages )
            logger.Debug( $"- {chartImage.caption()}" ) ;
        Program.mainForm.loadSearchResults( mChartImages, "HOTKEY:"+this, true ) ;
    }

    public override string textDescription() { return makeDescription( " ; ", false ) ; }
    public override string htmlDescription() { return makeDescription( "<br>", true ) ; }
    private string makeDescription( string sep, bool escape )
    {
        StringBuilder buf = new StringBuilder() ;
        for ( int i=0 ; i < mChartImages.Count ; ++i ) {
            if ( i > 0 )
                buf.Append( sep ) ;
            string caption = mChartImages[i].caption() ;
            buf.Append( escape ? SecurityElement.Escape(caption) : caption ) ;
        }
        return buf.ToString() ;
    }

    public void addChartImage( ChartImage ci ) { mChartImages.Add( ci ) ; }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

public class SearchQueryShortcut : Shortcut
{
    private string mSearchQuery ;

    public SearchQueryShortcut( Keys keys, string searchQuery ) : base( keys )
    {
        // initialize
        mSearchQuery = searchQuery ;
    }

    public override void executeShortcut()
    {
        // execute the shortcut
        Program.mainForm.setSearchQuery( mSearchQuery ) ;
        ILog logger = LogManager.GetLogger( "shortcuts" ) ;
        logger.Debug( $"- {mSearchQuery}" ) ;
    }

    public override string textDescription() { return mSearchQuery ; }
    public override string htmlDescription() { return SecurityElement.Escape( mSearchQuery ) ;
    }
}
