// $Id: chainstate.cpp,v 1.21 2018/01/03 21:33:03 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 "chainstate.h"
#include "tree.h"

// WARNING:  This code assumes that no operation changes more than one
// of the Tree, the Jointed Stick, and the Parameters at the same time!
// If such changes can occur this scheme will have to be heavily revised!

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

ChainState::ChainState()
    : m_tree(NULL),
      m_oldtree(NULL),
      m_parameters(global_region),
      m_oldparameters(global_region),
      //Since the ChainState works in region space, this will require that both
      // of these member variables get overwritten before being used.  In other
      // words, 'global_region' is wrong, and it's set to that on purpose
      // because it's a flag that it's wrong.
      unsampled_tree(true),
      unsampled_parameters(true),
      unsampled_stick(true),
      unsampled_map(true),
      unexported_parameters(true)
{
    // deliberately blank
} // ctor

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

ChainState::ChainState(const ChainState& src)
    : m_tree(src.m_tree), // yes, a shallow copy
      m_parameters(src.m_parameters),
      m_oldparameters(src.m_oldparameters),
      unsampled_tree(src.unsampled_tree),
      unsampled_parameters(src.unsampled_parameters),
      unsampled_stick(src.unsampled_stick),
      unsampled_map(src.unsampled_map),
      unexported_parameters(src.unexported_parameters)
{
    if (m_tree) m_oldtree = src.m_tree->Clone();  // deep copy
    else m_oldtree = NULL;
} // copy ctor

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

ChainState::~ChainState()
{
    delete m_oldtree;
} // dtor

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

ChainState& ChainState::operator=(const ChainState& src)
{
    m_tree = src.m_tree;  // yes, a shallow copy

    delete m_oldtree;
    if (m_tree) m_oldtree = src.m_tree->Clone();  // deep copy
    else m_oldtree = NULL;

    m_parameters = src.m_parameters;
    m_oldparameters = src.m_oldparameters;
    unsampled_tree = src.unsampled_tree;
    unsampled_parameters = src.unsampled_parameters;
    unsampled_stick = src.unsampled_stick;
    unsampled_map = src.unsampled_map;
    unexported_parameters = src.unexported_parameters;

    return *this;
} // operator=

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

void ChainState::SetTree(Tree* tree)
// This routine sets m_tree and then makes m_oldtree a tips-and-stump-and-stick
// copy of it
{
    assert(tree);   // We can't set things up with no tree!
    m_tree = tree;
    delete m_oldtree;
    m_oldtree = m_tree->MakeStump();
    m_oldtree->CopyTips(m_tree);
    m_oldtree->CopyStick(m_tree);
    TreeChanged();
    if (m_tree->UsingStick()) StickChanged();
    else unsampled_stick = false;

} // SetTree

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

void ChainState::SetOldTree(Tree* tree)
// This routine sets m_oldtree to be a full, valid copy of tree.
// Added October 2004 by erynes for use by ChainManager.
{
    assert(tree);   // We can't set things up with no tree!
    m_oldtree->CopyTips(tree);
    m_oldtree->CopyBody(tree);
    m_oldtree->CopyStick(tree);
    // NB This is called only at the start of a chain; therefore, it does
    // not need to mark the tree as modified.  Be careful if using it
    // anywhere else!  --Mary
} // SetOldTree

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

void ChainState::UpdateOldStickParams()
{
    m_oldtree->SetStickParams(m_parameters);
} // UpdateOldStickParams

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

void ChainState::UpdateNewStickParams()
{
    m_tree->SetStickParams(m_parameters);
} // UpdateNewStickParams

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

void ChainState::SimulateDataIfNeeded()
{
    assert(m_tree);   // We can't set things up with no tree!
    if (m_tree->SimulateDataIfNeeded())
    {
        //This changes the tips, so:
        m_oldtree->CopyTips(m_tree);
        m_oldtree->CopyBody(m_tree);
        // we assume the stick is still germane
    }
} // SimulateDataIfNeeded

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

void ChainState::SetParameters(const ForceParameters& params)
{
    m_parameters = params;
    ParametersChanged();
} // SetParameters

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

void ChainState::OverwriteOldTree()
{
    m_oldtree->CopyBody(m_tree);
    m_oldtree->CopyStick(m_tree);
} // OverwriteOldTree

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

void ChainState::OverwriteTree()
{
    m_tree->CopyBody(m_oldtree);
    m_tree->CopyStick(m_oldtree);
    TreeChanged();
} // OverwriteTree

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

void ChainState::OverwriteParameters()
{
    m_parameters = m_oldparameters;
} // OvewriteParameters

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

void ChainState::OverwriteOldParameters()
{
    m_oldparameters = m_parameters;
} // OvewriteOldParameters

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

void ChainState::TreeChanged()
{
    unsampled_tree = true;
    unsampled_map  = true;              // Only actually true if we're doing a floating
                                        // analysis, but probably not worth checking.
} // TreeChanged

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

void ChainState::ParametersChanged()
{
    unsampled_parameters = true;
    unexported_parameters = true;
} // ParametersChanged

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

void ChainState::StickChanged()
{
    unsampled_stick = true;
} // StickChanged

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

void ChainState::MapChanged()
{
    unsampled_map = true;
} // MapChanged

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

void ChainState::AllChanged()
{
    TreeChanged();
    ParametersChanged();
    if (m_tree->UsingStick())
    {
        StickChanged();
    }
    MapChanged();
} // AllChanged

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

void ChainState::SwapParameters(ChainState& other)
{
    std::swap(m_parameters, other.m_parameters);
    std::swap(m_oldparameters, other.m_oldparameters);
    ParametersChanged();
    other.ParametersChanged();
} // SwapParameters

//____________________________________________________________________________________
