/*
 * Copyright (c) 2002-2006 Samit Basu
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include "HandleObject.hpp"
#include "HandleAxis.hpp"
#include "HandleList.hpp"
#include "HandleFigure.hpp"
#include "HandleCommands.hpp"
#include "Core.hpp"
#include "IEEEFP.hpp"

bool HandleObject::IsType(std::string name) {
  HPString* sp = (HPString*) LookupProperty("type");
  return (sp->Is(name));
}

void HandleObject::ToManual(std::string name) {
  HPAutoManual *qp = (HPAutoManual*) LookupProperty(name);
  qp->Data("manual");
}

bool HandleObject::HasChanged(std::vector<std::string> names) {
  HandleProperty *hp;
  for (int i=0;i<names.size();i++) {
    hp = LookupProperty(names[i]);
    if (hp->isModified()) return true;
  }
  return false;
}

bool HandleObject::HasChanged(std::string name) {
  std::vector<std::string> names;
  names.push_back(name);
  return HasChanged(names);
}

void HandleObject::ClearAllChanged() {
  std::vector<std::string> names(m_properties.getCompletions(""));
  ClearChanged(names);
}

void HandleObject::ClearChanged(std::vector<std::string> names) {
  HandleProperty *hp;
  for (int i=0;i<names.size();i++) {
    hp = LookupProperty(names[i]);
    hp->ClearModified();
  }    
}

void HandleObject::ClearChanged(std::string name) {
  HandleProperty *hp;
  hp = LookupProperty(name);
  hp->ClearModified();
}

HandleObject::HandleObject() {
  ref_count = 1;
}

HandleObject::~HandleObject() {
  // Loop through our children
  HPHandles *hp = (HPHandles*) LookupProperty("children");
  HandleObject *gp;
  std::vector<unsigned> my_children(hp->Data());
  for (int i=0;i<my_children.size();i++) {
    unsigned handle = my_children[i];
    if (handle >= HANDLE_OFFSET_OBJECT) {
      gp = LookupHandleObject(handle);
      gp->Dereference();
      if (gp->RefCount() <= 0) {
	//	  qDebug("Deleting handle %d\n",handle);
	FreeHandleObject(handle);
	delete gp;
      }
    }
  }
  // Delete our properties also
  stringVector propSet(m_properties.getCompletions(""));
  for (int i=0;i<propSet.size();i++) {
    HandleProperty** hp = m_properties.findSymbol(propSet[i]);
    if (hp) delete (*hp);
  }
}

HandleProperty* HandleObject::LookupProperty(std::string name) {
  std::transform(name.begin(),name.end(),name.begin(),
		 (int(*)(int))tolower);
  // First look for the property to match (avoids the problem
  // with prefix names)
  HandleProperty** hp = m_properties.findSymbol(name);
  if (hp) return (*hp);
  //complete it
  stringVector completes(m_properties.getCompletions(name));
  if (completes.empty())
    throw Exception("invalid property " + name);
  if (completes.size() != 1)
    throw Exception("ambiguous property name " + name);
  hp = m_properties.findSymbol(completes[0]);
  return *hp;
}

void HandleObject::SetPropertyHandle(std::string name, unsigned value) {
  HPHandles* hp = (HPHandles*) LookupProperty(name);
  std::vector<unsigned> newval;
  newval.push_back(value);
  hp->Data(newval);
}

HandleAxis* HandleObject::GetParentAxis() {
  // Get our parent - must be an axis
  HPHandles *parent = (HPHandles*) LookupProperty("parent");
  if (parent->Data().empty()) return NULL;
  unsigned parent_handle = parent->Data()[0];
  HandleObject *fp = LookupHandleObject(parent_handle);
  HPString *name = (HPString*) fp->LookupProperty("type");
  if (!name) return NULL;
  if (!name->Is("axes")) return NULL;
  HandleAxis *axis = (HandleAxis*) fp;
  return axis;
}

HandleFigure* HandleObject::GetParentFigure() {
  HandleAxis* hp;
  if (StringCheck("type","axes")) 
    hp = (HandleAxis*) this;
  else
    hp = GetParentAxis();
  // Get our parent - must be an axis
  HPHandles *parent = (HPHandles*) hp->LookupProperty("parent");
  if (parent->Data().empty()) return NULL;
  unsigned parent_handle = parent->Data()[0];
  return LookupHandleFigure(parent_handle);
}

void HandleObject::MarkDirty() {
  HandleFigure *fp = GetParentFigure();
  if (fp)
    fp->UpdateState();
}

std::string HandleObject::StringPropertyLookup(std::string name) {
  HPString* sp = (HPString*) LookupProperty(name);
  return (sp->Data());
}

std::vector<double> HandleObject::VectorPropertyLookup(std::string name) {
  HPVector* sp = (HPVector*) LookupProperty(name);
  return (sp->Data());
}

Array HandleObject::ArrayPropertyLookup(std::string name) {
  HPArray* hp = (HPArray*) LookupProperty(name);
  return (hp->Data());
}
  
double HandleObject::ScalarPropertyLookup(std::string name) {
  HPScalar* sp = (HPScalar*) LookupProperty(name);
  return (sp->Data()[0]);
}

unsigned HandleObject::HandlePropertyLookup(std::string name) {
  HPHandles* sp = (HPHandles*) LookupProperty(name);
  if (sp->Data().empty())
    return 0;
  else
    return (sp->Data()[0]);
}

void HandleObject::AddProperty(HandleProperty* hp, std::string name) {
  m_properties.insertSymbol(name,hp);
}

void HandleObject::SetConstrainedStringScalarDefault(std::string name,
						     std::string value,
						     double sval) {
  HPConstrainedStringScalar *hp = 
    (HPConstrainedStringScalar*) LookupProperty(name);
  if (!hp)
    throw Exception("constrained string/scalar default failed lookup of <" + 
		    name + ">");
  hp->Value(value);
  hp->Scalar(sval);
}

void HandleObject::SetConstrainedStringColorDefault(std::string name,
						    std::string value,
						    double red, 
						    double green,
						    double blue) {
  HPConstrainedStringColor *hp = 
    (HPConstrainedStringColor*) LookupProperty(name);
  if (!hp)
    throw Exception("constrained string/color default failed lookup of <" +
		    name + ">");
  hp->Value(value);
  hp->ColorSpec(red,green,blue);
}
						     

void HandleObject::SetConstrainedStringDefault(std::string name, std::string value) {
  HPConstrainedString *hp = (HPConstrainedString*) LookupProperty(name);
  if (!hp)
    throw Exception("set constrained string default failed lookup of <" + name + ">");
  hp->Value(value);
}

void HandleObject::SetConstrainedStringSetDefault(std::string name, std::string values) {
  HPConstrainedStringSet *hp = (HPConstrainedStringSet*) LookupProperty(name);
  std::vector<std::string> data;
  Tokenize(values,data,"|");
  ((HPStringSet*)hp)->Data(data);
}

void HandleObject::SetThreeVectorDefault(std::string name, double x, double y, double z) {
  HPThreeVector *hp = (HPThreeVector*) LookupProperty(name);
  hp->Value(x,y,z);
}

void HandleObject::SetFourVectorDefault(std::string name, double x, double y,
					double z, double w) {
  HPFourVector *hp = (HPFourVector*) LookupProperty(name);
  hp->Value(x,y,z,w);
}

void HandleObject::SetTwoVectorDefault(std::string name, double x, double y) {
  HPTwoVector *hp = (HPTwoVector*) LookupProperty(name);
  hp->Value(x,y);
}

void HandleObject::SetStringDefault(std::string name, std::string value) {
  HPString *hp = (HPString*) LookupProperty(name);
  hp->Value(value);
}

void HandleObject::SetScalarDefault(std::string name, double value) {
  HPScalar *hp = (HPScalar*) LookupProperty(name);
  hp->Value(value);
}

bool HandleObject::IsAuto(std::string mode) {
  HPAutoManual *hp = (HPAutoManual*) LookupProperty(mode);
  return hp->Is("auto");
}
  
bool HandleObject::StringCheck(std::string name, std::string value) {
  HPString *hp = (HPString*) LookupProperty(name);
  return hp->Is(value);
}

double VecMin(std::vector<double> &v) {
  double min = 0;
  bool first = true;
  for (int i=0;i<v.size();i++) {
    if (IsFinite(v[i]))
      if (first) {
	first = false;
	min = v[i];
      } else if (v[i] < min) {
	min = v[i];
      }
  }
  return min;
}

double VecMax(std::vector<double> &v) {
  double max = 0;
  bool first = true;
  for (int i=0;i<v.size();i++) {
    if (IsFinite(v[i]))
      if (first) {
	first = false;
	max = v[i];
      } else if (v[i] > max) {
	max = v[i];
      }
  }
  return max;
}

double ArrayMin(Array a) {
  if (a.isEmpty()) return 0;
  a.promoteType(FM_DOUBLE);
  const double* v = (const double *) a.getDataPointer();
  int len = a.getLength();
  double min = 0;
  bool first = true;
  for (int i=0;i<len;i++) {
    if (IsFinite(v[i]))
      if (first) {
	first = false;
	min = v[i];
      } else if (v[i] < min) {
	min = v[i];
      }
  }
  return min;
}

double ArrayMax(Array a) {
  if (a.isEmpty()) return 0;
  a.promoteType(FM_DOUBLE);
  const double* v = (const double *) a.getDataPointer();
  int len = a.getLength();
  double max = 0;
  bool first = true;
  for (int i=0;i<len;i++) {
    if (IsFinite(v[i]))
      if (first) {
	first = false;
	max = v[i];
      } else if (v[i] > max) {
	max = v[i];
      }
  }
  return max;
}


syntax highlighted by Code2HTML, v. 0.9.1