// Copyright (C) 1999-2015
// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
// For conditions of distribution and use, see copyright notice in "copyright"

#include <tk.h>

#include "basemarker.h"
#include "base.h"

// Base Markers Public

BaseMarker::BaseMarker(Base* p, const Vector& ctr, double ang)
  : Marker(p, ctr, ang)
{
  startAng_ = 0;
  stopAng_ = M_TWOPI;

  numAnnuli_ = 0;
  annuli_ = NULL;
}

BaseMarker::BaseMarker(Base* p, const Vector& ctr, double ang,
		       const char* clr, int* dsh, 
		       int w, const char* f, 
		       const char* t, unsigned short prop, const char* c,
		       const List<Tag>& tag, const List<CallBack>& cb)
  : Marker(p, ctr, ang, clr, dsh, w, f, t, prop, c, tag, cb)
{
  startAng_ = 0;
  stopAng_ = M_TWOPI;

  numAnnuli_ = 0;
  annuli_ = NULL;
}

BaseMarker::BaseMarker(const BaseMarker& a) : Marker(a)
{
  startAng_ = a.startAng_;
  stopAng_ = a.stopAng_;

  numAnnuli_ = a.numAnnuli_;
  annuli_ = new Vector[a.numAnnuli_];
  for (int i=0; i<a.numAnnuli_; i++)
    annuli_[i] = a.annuli_[i];
}

BaseMarker::~BaseMarker()
{
  if (annuli_)
    delete [] annuli_;
}

void BaseMarker::updateCoords(const Matrix& mx)
{
  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] *= Scale(mx);

  Marker::updateCoords(mx);
}

void BaseMarker::setAnnuli(const Vector& r)
{
  annuli_[0] = r;
  updateBBox();

  doCallBack(CallBack::EDITCB);
}

void BaseMarker::setAnnuli(const Vector& r1, const Vector& r2, int rn)
{
  numAnnuli_ = rn+1;
  if (annuli_)
    delete [] annuli_;
  annuli_ = new Vector[numAnnuli_];

  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] = ((r2-r1)/rn)*i+r1;
  sortAnnuli();

  numHandle = 4 + numAnnuli_;

  updateBBox();
  doCallBack(CallBack::EDITCB);
}

void BaseMarker::setAnnuli(const Vector* r, int rn)
{
  numAnnuli_ = rn;
  if (annuli_)
    delete [] annuli_;
  annuli_ = new Vector[numAnnuli_];

  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] = r[i];
  sortAnnuli();

  numHandle = 4 + numAnnuli_;

  updateBBox();
  doCallBack(CallBack::EDITCB);
}

int BaseMarker::insertAnnuli(Vector r)
{
  // new size array
  Vector* old = annuli_;
  annuli_ = new Vector[numAnnuli_+1];

  // copy old values
  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] = old[i];

  // delete old
  if (old)
    delete [] old;

  // new size on end
  annuli_[numAnnuli_] = r;

  numAnnuli_++;
  numHandle++;

  updateBBox();

  // return handle number
  return numAnnuli_+4;
}

void BaseMarker::deleteAnnuli(int h)
{
  if (h>4) {
    int hh = h-4-1;

    if (numAnnuli_>2 && hh<numAnnuli_) {
      // new radii array
      Vector* old = annuli_;
      annuli_ = new Vector[numAnnuli_-1];

      // copy up to radii in question
      for (int i=0; i<hh; i++)
	annuli_[i] = old[i];

      // copy remainder
      for (int i=hh; i<numAnnuli_-1; i++)
	annuli_[i] = old[i+1];

      if (old)
	delete [] old;
      numAnnuli_--;

      numHandle = 4 + numAnnuli_;

      updateBBox();
      doCallBack(CallBack::EDITCB);
    }
  }
}

void BaseMarker::sortAnnuli()
{
  for (int i=0; i<numAnnuli_; i++)
    for (int j=i+1; j<numAnnuli_; j++)
      if (annuli_[i][0]>annuli_[j][0]) {
	Vector d = annuli_[i];
	annuli_[i] = annuli_[j];
	annuli_[j] = d;
      }
}

Matrix BaseMarker::fwdMatrix()
{
  if (properties & FIXED) {
    Vector cc = center * parent->refToCanvas;
    return Rotate(calcAngle()) * Translate(cc) * parent->canvasToRef;
  }
  else
    return Marker::fwdMatrix();
}

Matrix BaseMarker::bckMatrix()
{
  if (properties & FIXED) {
    Vector cc = center * parent->refToCanvas;
    return parent->refToCanvas * Translate(-cc) * Rotate(-calcAngle());
  }
  else
    return Marker::bckMatrix();
}

Vector BaseMarker::fwdMap(const Vector& vv, Coord::InternalSystem sys)
{
  if (properties & FIXED) {
    Vector cc = center * parent->refToCanvas;
    Vector dd = vv * Rotate(calcAngle()) * Translate(cc);
    Vector ee = dd*parent->canvasToRef;
    return parent->mapFromRef(ee,sys);
  }
  else
    return Marker::fwdMap(vv,sys);
}

Vector BaseMarker::bckMap(const Vector& vv, Coord::InternalSystem sys)
{
  if (properties & FIXED) {
    Vector aa = parent->mapToRef(vv,sys);
    Vector bb = aa*parent->refToCanvas;
    Vector cc = center * parent->refToCanvas;
    return bb * Translate(-cc) * Rotate(-calcAngle());
  }
  else
    return Marker::bckMap(vv,sys);
}

