// $Id: newmenu.cpp,v 1.31 2018/01/03 21:33:01 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


#include <cassert>
#include <string>
#include <vector>

#include "menuinteraction.h"
#include "display.h"
#include "newmenu.h"
#include "errhandling.h"
#include "menudefs.h"
#include "menuitem.h"
#include "menu_strings.h"
#include "newmenuitems.h"
#include "ui_interface.h"
#include "constants.h"
#include "stringx.h"

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

void NewMenu::fillStandardContent(bool atTop)
{
    beforeContent.push_back(new BlankMenuItem());
    //
    afterContent.push_back(new DividerMenuItem());
    if(atTop)
    {
        afterContent.push_back(new BottomLineMenuItemAtTop(ui));
    }
    else
    {
        afterContent.push_back(new BottomLineMenuItem(ui));
    }
    afterContent.push_back(new UndoMenuItem(ui));
    afterContent.push_back(new RedoMenuItem(ui));
    afterContent.push_back(new FileDumpMenuItem(ui));
}

NewMenu::NewMenu(UIInterface & myui, const std::string myTitle, bool atTop)
    : MenuInteraction(), ui(myui), title(myTitle), info (menustr::emptyString)
{
    fillStandardContent(atTop);
}

NewMenu::NewMenu(UIInterface & myui, const std::string myTitle, const std::string myInfo, bool atTop)
    : MenuInteraction(), ui(myui), title(myTitle), info (myInfo)
{
    fillStandardContent(atTop);
}

NewMenu::~NewMenu()
{
    afterContent.NukeContents();
    afterContent.clear();
    beforeContent.NukeContents();
    beforeContent.clear();
    myContent.NukeContents();
    myContent.clear();
}

void NewMenu::AddMenuItem(MenuDisplayQuanta * menuItem)
{
    //Check to see if we already use this key.
#ifndef NDEBUG
    MenuDisplayLine * newmenuline = dynamic_cast<MenuDisplayLine*>(menuItem);
    if (newmenuline != NULL)
    {
        string newkey = newmenuline->GetKey();
        if (newkey != menustr::emptyString)
        {
            if (Handles(newkey))
            {
                string msg = "The menu key for \"" + newmenuline->GetText() +
                    "\" (" + newkey + ") is already used by another menu item.";
                throw implementation_error(msg);
            }
        }
    }
#endif
    //We're safe--add it.
    myContent.push_back(menuItem);
}

// returns true if this menu knows how to respond to the given input
bool NewMenu::Handles(std::string input)
{
    MenuDisplayQuantaVec allContent = MenuItems();
    MenuDisplayQuantaVec::iterator i;
    for(i=allContent.begin(); i!=allContent.end(); i++)
    {
        MenuDisplayQuanta * base = *i;
        MenuDisplayQuantaWithHandler * item
            = dynamic_cast<MenuDisplayQuantaWithHandler*>(base);
        if(item != NULL)
        {
            if(item->Handles(input))
            {
                return true;
            }
        }
    }
    return false;
}

MenuInteraction_ptr NewMenu::GetHandler(std::string input)
{
    MenuDisplayQuantaVec allContent = MenuItems();
    MenuDisplayQuantaVec::iterator i;
    for(i=allContent.begin(); i!=allContent.end(); i++)
    {
        MenuDisplayQuanta * base = *i;
        MenuDisplayQuantaWithHandler * item
            = dynamic_cast<MenuDisplayQuantaWithHandler*>(base);
        if(item != NULL)
        {
            if(item->Handles(input))
            {
                MenuInteraction_ptr mi = item->GetHandler(input);
                return mi;
            }
        }
    }
    assert(false);
    return MenuInteraction_ptr(NULL);
}

menu_return_type NewMenu::InvokeMe(Display& display)
{
    return display.DisplayNewMenu(*this);
}

std::string NewMenu::Title()
{
    return title;
}

StringVec1d NewMenu::Warnings()
{
    return ui.GetAndClearWarnings();
}

void NewMenu::AddWarning(string warning)
{
    ui.AddWarning(warning);
}

std::string NewMenu::Info()
{
    return info;
}

MenuDisplayQuantaVec NewMenu::MenuItems()
{
    MenuDisplayQuantaVec allContent;
    allContent.insert(allContent.end(),beforeContent.begin(),beforeContent.end());
    allContent.insert(allContent.end(),myContent.begin(),myContent.end());
    allContent.insert(allContent.end(),afterContent.begin(),afterContent.end());
    return allContent;
}

StringVec1d NewMenu::GetInconsistencies()
{
    StringVec1d inconsistents;
    MenuDisplayQuantaVec :: iterator i;
    for(i = myContent.begin(); i != myContent.end(); i++)
    {
        MenuDisplayQuanta * base = *i;
        MenuDisplayLine * line = dynamic_cast<MenuDisplayLine*>(base);
        if(line != NULL)
        {
            if(line->IsVisible())
            {
                if(!line->IsConsistent())
                {
                    inconsistents.push_back(line->GetKey());
                }
            }
        }
        MenuDisplayGroup * group = dynamic_cast<MenuDisplayGroup*>(base);
        if(group != NULL)
        {
            std::vector<UIId> inconsistentIds = group->GetInconsistentIds();
            std::vector<UIId> :: iterator i;
            for(i = inconsistentIds.begin(); i != inconsistentIds.end(); i++)
            {
                inconsistents.push_back(group->GetKey(*i));
            }
        }
    }
    return inconsistents;
}

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

NewMenuCreator::NewMenuCreator()
{
}

NewMenuCreator::~NewMenuCreator()
{
}

//____________________________________________________________________________________
