/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

//
// Drop Action class
//

#include "DropAction.h"
#include "Presentable.h"
#include "Root.h"
#include "ObjectList.h"
#include "PlotMod.h"
#include "MvLog.h"

void DropAction::Execute(PmContext& context)
{
    // Check whether an application was dropped.
    // If so, the drop will contain a _MODE request.
    // Call a routine to go through the context and add info from _MODE request
    // at first data unit. This is done for macro generation to work correctly
    // and should not affect other uses.
    if (context.InRequest().getSubrequest("_MODE"))
        PrepareForMacro(context);

    // Find the location on the Tree
    // Find the DROP_ID associated to the DROP request
    MvRequest dropRequest = context.InRequest();
    int treeNodeId = dropRequest("DROP_ID");
    if (treeNodeId == 0) {
        context.Advance();  // Skip DROP request
        return;
    }

    // Special case when an object was dropped in a
    // DataUnit at Contents window
    /// F	int presentableId = dropRequest("PRESENTABLE_ID");
    /// F	if ( presentableId == 0 )
    /// F	  presentableId = treeNodeId;
    int contentsWindow = dropRequest("_CONTENTS");
    int dataUnitId = dropRequest("_CONTENTS_DATAUNIT_ID");
    int calledFromMacro = dropRequest("_CALLED_FROM_MACRO");
    context.Advance();  // Skip DROP request

    // Find the tree node associated to the DropId
    Presentable* treeNode = Root::Instance().FindBranch(treeNodeId);
    if (treeNode == nullptr) {
        MvLog().popup().warn() << "uPlot DropAction::Execute-> Cannot associate page with DropId: " << treeNodeId;
        return;
    }

    treeNode->SetContentsDataUnit(dataUnitId);  // set Contents flag
                                                /// F	treeNode->DroppedHere ( presentableId );
    // Needs redrawing by default. This may be overrulled by the Drop function
    treeNode->NeedsRedrawing(true);
    treeNode->DroppedHere(treeNodeId);
    treeNode->SetDropShouldStay(contentsWindow | calledFromMacro);  // Drop from Contents or macro

    // The Drop method should call context.Advance()
    treeNode->Drop(context);
    treeNode->DroppedHere(0);  // assuming presentableId_ > 0
    treeNode->HasDrawTask(true);
    treeNode->SetContentsDataUnit(0);  // reset Contents flag

    // Advance to end after we've done the drop
    context.AdvanceToEnd();
}

/// This function should only kick in if an application is dropped
void DropAction::PrepareForMacro(PmContext& context)
{
    MvRequest newRequest = context.InRequest();
    MvRequest inMode = newRequest.getSubrequest("_MODE");
    const char* inClass = (const char*)inMode("_CLASS");
    const char* inVerb = (const char*)inMode("_VERB");
    const char* inName = (const char*)inMode("_NAME");

    const char* firstDataUnit = "";
    while (newRequest) {
        // We normally have a CLEAN request which will
        // have values for _CLASS,_NAME and _VERB, so
        // fill these in if we didn't get them from mode.
        if (strcmp(newRequest.getVerb(), "CLEAN") == 0 &&
            strcmp(firstDataUnit, "") == 0) {
            if (!inClass)
                inClass = (const char*)newRequest("_CLASS");

            if (!inVerb)
                inVerb = (const char*)newRequest("_VERB");

            if (!inName)
                inName = (const char*)newRequest("_NAME");
        }

        if (ObjectList::IsDataUnit(newRequest.getVerb()) &&
            strcmp(firstDataUnit, "") == 0) {
            if (!((const char*)newRequest("_CLASS")))
                newRequest("_CLASS") = inClass;

            if (!((const char*)newRequest("_VERB")))
                newRequest("_VERB") = inVerb;

            if (!((const char*)newRequest("_NAME")))
                newRequest("_NAME") = inName;

            newRequest("_MODE") = inMode;
            newRequest("_USE_MODE") = 1;
            firstDataUnit = newRequest.getVerb();
        }
        else
            newRequest("_SKIP_MACRO") = 1;

        newRequest.advance();
    }

    newRequest.rewind();
    context.Update(newRequest);
}

//
// This is the exemplar object for the Drop Action class
//
static DropAction dropActionInstance("Drop");
