#include "location.h"
using namespace hub;
// ----------------------------------------------------------------------------
Location :: Location (Hub* h, const std::string& lab) :
label_(lab),
theArch_  	(NULL),			fixedArch_(false),
theEntity_ 	(NULL),			fixedEntity_(false),
theLib_ 	(NULL),			fixedLib_(false),
theDesign_  (NULL),         fixedDesign_(false),
theHub_ 	(h)
{}

// ----------------------------------------------------------------------------
Location :: Location (Hub* h) :
theArch_  	(NULL),			fixedArch_(false),
theEntity_ 	(NULL),			fixedEntity_(false),
theLib_ 	(NULL),			fixedLib_(false),
theDesign_  (NULL),         fixedDesign_(false),
theHub_ 	(h)
{}

// ----------------------------------------------------------------------------
Location :: Location (const Location& loc) :
label_      (loc.label_),
theArch_  	(loc.theArch_),			fixedArch_(loc.fixedArch_),
theEntity_ 	(loc.theEntity_),		fixedEntity_(loc.fixedEntity_),
theLib_ 	(loc.theLib_),			fixedLib_(loc.fixedLib_),
theDesign_  (loc.theDesign_),        fixedDesign_(loc.fixedDesign_),
theHub_ 	(loc.theHub_) {
    items_[design] = loc.items_[design];
    items_[arch]   = loc.items_[arch];
    items_[ent]    = loc.items_[ent];
    items_[lib]    = loc.items_[lib]; 
}

// ----------------------------------------------------------------------------
//  Reset(): initiate search again
// ----------------------------------------------------------------------------
void Location :: Reset (void) {
    theArch_   = NULL; 
    theEntity_ = NULL;
    theLib_    = NULL;
}
// ----------------------------------------------------------------------------
//  Inherit(): take over values for fields that are not locked
// ----------------------------------------------------------------------------
void Location :: Inherit (const Location& that) {
    if (!items_[lib].locked()) items_[lib].content (that.items_[lib].content());
    if (!items_[ent].locked()) items_[ent].content (that.items_[ent].content());
    if (!items_[arch].locked()) items_[arch].content (that.items_[arch].content());
    if (!items_[design].locked()) items_[design].content (that.items_[design].content());
}
// ----------------------------------------------------------------------------
//	FindOrCreate(): specifying destination
// ----------------------------------------------------------------------------
InconsReason Location :: FindOrCreate (void) {
    // provisions for successive evaluation: 
    // existing pointers preserved until reset
    // ------  find/create library: could be taken over from an existing design?
    if (!theLib_) {
        if (items_[lib].empty()) {
            if (items_[lib].oblig()) {
                return InconsReason ("Library not specified");
            } else {
                theLib_ = NULL;
                fixedLib_ = false;
            }
        } else {
            theLib_ = theHub_->FindOrCreateLib (items_[lib].content());
            fixedLib_ = true;
        }
    }

    // ------ find/create entity ------------------------------------------------
    if (!theEntity_) {
        if (items_[ent].empty()) {
            if (items_[ent].oblig()) {
                return InconsReason ("Entity not specified");
            } else {
                theEntity_ = NULL;
                fixedEntity_ = false;
            }
        } else {
            if (theLib_) {
                theEntity_ = theLib_->FindOrCreateEntity (items_[ent].content());
            } else {
                theEntity_ = NULL;
            }
        }
    }
    // ------ find/create architecture --------------------------------------------
    if (!theArch_) {
        if (items_[arch].empty()) {
            if (items_[arch].oblig()) {
                return InconsReason ("Architecture not specified");
            } else {
                theArch_ = NULL;
                fixedArch_ = false;
            }
        } else {
            if (theEntity_) {       // ask for permission to overwrite existing arch
                theArch_ = theEntity_->FindOrCreateArch (items_[arch].content());
            } else {
                theArch_ = NULL;
            }
        }
    }
    return InconsReason (0);
}
// ----------------------------------------------------------------------------
//	FindOrCreateDesign(): specifying destination
// ----------------------------------------------------------------------------
InconsReason Location :: FindOrCreateDesign (void) {
    if (!items_[design].empty()) {
        if (!theEntity_) return InconsReason ("Design entity unknown");
        theDesign_ = theHub_->FindDesign (items_[design].content());
        if (theDesign_) {
            theDesign_->DesignEntity (theEntity_);
            std::cout << "Found design " << theDesign_->name() << std::endl;
        } else {
            theDesign_ = theHub_->CreateDesign (items_[design].content(), theEntity_, theLib_);
            std::cout << "Created design " << theDesign_->name() << std::endl;
        }
    }
    return InconsReason (0);
}
// ---------------------------------------------------------------------------------
//      Find(): specifying a source location
// ---------------------------------------------------------------------------------
InconsReason Location :: Find (void) {

    // ------- design given - means entity & library ---------
    if (!items_[design].empty()) {
        Design* des = theHub_->FindDesign (items_[design].content());
        if (!des) return InconsReason ("Specified design does not exist");
        theEntity_ = des->DesignEntity();   fixedEntity_ = true;
        theLib_ = theEntity_->Parent();     fixedLib_    = true;
        fixedDesign_ = true;
    } else {
        fixedDesign_ = false;
        // --- design not given, get entity & library --------
        if (!theLib_) {                  // honor existing values
            if (items_[lib].empty()) {
                if (items_[lib].oblig()) {
                    return InconsReason ("Library not specified");
                } else {
                    theLib_ = NULL;
                    fixedLib_ = false;
                }
            } else {
                theLib_ = theHub_->FindLib (items_[lib].content());
                if (!theLib_) return InconsReason ("The specified library does not exist");
                fixedLib_ = true;
            }
        }

        if (!theEntity_) {
            if (items_[ent].empty()) {
                if (items_[ent].oblig()) {
                    return InconsReason ("Entity not specified");
                } else {
                    theEntity_ = NULL;
                    fixedEntity_ = false;
                }
            } else {
                if (theLib_) {
                    theEntity_ = theLib_->FindEntity (items_[ent].content());
                    if (!theEntity_) return InconsReason ("The specified entity does not exist");
                    fixedEntity_ = true; 
                } else {
                    theEntity_ = NULL;
                    fixedEntity_ = true;        // unknown yet but specified by name
                }
            }
        }
    }
    if (!theArch_) {
        if (items_[arch].empty()) {
            if (items_[arch].oblig()) {
                return InconsReason ("Architecture not specified");
            } else {
                theArch_ = NULL;
                fixedArch_ = false;
            }
        } else {
            if (theEntity_) {
                theArch_ = theEntity_->FindArch (items_[arch].content());
                if (!theArch_) return InconsReason ("The specified architecture does not exist");
                fixedArch_ = true; 
            } else {
                theArch_ = NULL;
                fixedArch_ = true;      // unknown but named
            }
        }
    }
    return InconsReason (0);
}
// ---------------------------------------------------------------------------------
//      FindDesign(): specifying a source location or checking
// ---------------------------------------------------------------------------------
InconsReason Location :: FindDesign (void) {
    if (!items_[design].empty()) {
        Design* des = theHub_->FindDesign (items_[design].content());
        if (!des) return InconsReason ("Specified design does not exist");
        theEntity_ = des->DesignEntity();   fixedEntity_ = true;
        theLib_ = theEntity_->Parent();     fixedLib_    = true;
        fixedDesign_ = true;
    } 
    return InconsReason (0);
}
