//============================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//
//  Copyright 2016 Sandia Corporation.
//  Copyright 2016 UT-Battelle, LLC.
//  Copyright 2016 Los Alamos National Security.
//
//  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
//  the U.S. Government retains certain rights in this software.
//
//  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
//  Laboratory (LANL), the U.S. Government retains certain rights in
//  this software.
//============================================================================

#include <vtkm/rendering/AxisAnnotation2D.h>

#include <vtkm/rendering/TextAnnotationScreen.h>

#include <sstream>

namespace vtkm {
namespace rendering {

AxisAnnotation2D::AxisAnnotation2D()
  : AxisAnnotation()
{
  this->AlignH = TextAnnotation::HCenter;
  this->AlignV = TextAnnotation::VCenter;
  this->FontScale = 0.05f;
  this->LineWidth = 1.0;
  this->Color = vtkm::rendering::Color(1,1,1);
  this->Logarithmic = false;
  this->MoreOrLessTickAdjustment = 0;
}

AxisAnnotation2D::~AxisAnnotation2D()
{

}

void AxisAnnotation2D::SetRangeForAutoTicks(const Range &range)
{
  this->TickRange = range;

#if 0
  if (this->Logarithmic)
  {
    CalculateTicksLogarithmic(this->TickRange.Min,
                              this->TickRange.Max,
                              false,
                              this->PositionsMajor,
                              this->ProportionsMajor,
                              this->MoreOrLessTickAdjustment);
    CalculateTicksLogarithmic(this->TickRange.Min,
                              this->TickRange.Max,
                              true,
                              this->PositionsMinor,
                              this->ProportionsMinor,
                              this->MoreOrLessTickAdjustment);
  }
  else
#endif
  {
    CalculateTicks(this->TickRange,
                   false,
                   this->PositionsMajor,
                   this->ProportionsMajor,
                   this->MoreOrLessTickAdjustment);
    CalculateTicks(this->TickRange,
                   true,
                   this->PositionsMinor,
                   this->ProportionsMinor,
                   this->MoreOrLessTickAdjustment);
  }
}

void AxisAnnotation2D::SetMajorTicks(const std::vector<vtkm::Float64> &pos,
                                     const std::vector<vtkm::Float64> &prop)
{
  this->PositionsMajor.clear();
  this->PositionsMajor.insert(this->PositionsMajor.begin(),
                              pos.begin(),
                              pos.end());

  this->ProportionsMajor.clear();
  this->ProportionsMajor.insert(this->ProportionsMajor.begin(),
                                prop.begin(),
                                prop.end());
}

void AxisAnnotation2D::SetMinorTicks(const std::vector<vtkm::Float64> &pos,
                                     const std::vector<vtkm::Float64> &prop)
{
  this->PositionsMinor.clear();
  this->PositionsMinor.insert(this->PositionsMinor.begin(), pos.begin(), pos.end());

  this->ProportionsMinor.clear();
  this->ProportionsMinor.insert(this->ProportionsMinor.begin(), prop.begin(), prop.end());
}

void AxisAnnotation2D::Render(
    const vtkm::rendering::Camera &camera,
    const vtkm::rendering::WorldAnnotator &worldAnnotator,
    vtkm::rendering::Canvas &canvas)
{
  canvas.AddLine(this->PosX0,this->PosY0, this->PosX1,this->PosY1, this->LineWidth, this->Color);

  // major ticks
  unsigned int nmajor = (unsigned int)this->ProportionsMajor.size();
  while (this->Labels.size() < nmajor)
  {
      this->Labels.push_back(new vtkm::rendering::TextAnnotationScreen(
                               "test",
                               this->Color,
                               this->FontScale,
                               vtkm::Vec<vtkm::Float32,2>(0,0),
                               0));
  }

  std::stringstream numberToString;
  for (unsigned int i=0; i<nmajor; ++i)
  {
    vtkm::Float64 xc = this->PosX0 + (this->PosX1-this->PosX0) * this->ProportionsMajor[i];
    vtkm::Float64 yc = this->PosY0 + (this->PosY1-this->PosY0) * this->ProportionsMajor[i];
    vtkm::Float64 xs = xc - this->MajorTickSizeX*this->MajorTickOffset;
    vtkm::Float64 xe = xc + this->MajorTickSizeX*(1. - this->MajorTickOffset);
    vtkm::Float64 ys = yc - this->MajorTickSizeY*this->MajorTickOffset;
    vtkm::Float64 ye = yc + this->MajorTickSizeY*(1. - this->MajorTickOffset);

    canvas.AddLine(xs,ys, xe,ye, 1.0, this->Color);

    if (this->MajorTickSizeY == 0)
    {
      // slight shift to space between label and tick
      xs -= (this->MajorTickSizeX<0?-1.:+1.) * this->FontScale * .1;
    }

    numberToString.str("");
    numberToString << this->PositionsMajor[i];

    this->Labels[i]->SetText(numberToString.str());
    //if (fabs(this->PositionsMajor[i]) < 1e-10)
    //    this->Labels[i]->SetText("0");
    ((TextAnnotationScreen*)(this->Labels[i]))->SetPosition(vtkm::Float32(xs),
                                                            vtkm::Float32(ys));

    this->Labels[i]->SetAlignment(this->AlignH,this->AlignV);
  }

  // minor ticks
  if (this->MinorTickSizeX != 0 || this->MinorTickSizeY != 0)
  {
    unsigned int nminor = (unsigned int)this->ProportionsMinor.size();
    for (unsigned int i=0; i<nminor; ++i)
    {
      vtkm::Float64 xc = this->PosX0 + (this->PosX1-this->PosX0) * this->ProportionsMinor[i];
      vtkm::Float64 yc = this->PosY0 + (this->PosY1-this->PosY0) * this->ProportionsMinor[i];
      vtkm::Float64 xs = xc - this->MinorTickSizeX*this->MinorTickOffset;
      vtkm::Float64 xe = xc + this->MinorTickSizeX*(1. - this->MinorTickOffset);
      vtkm::Float64 ys = yc - this->MinorTickSizeY*this->MinorTickOffset;
      vtkm::Float64 ye = yc + this->MinorTickSizeY*(1. - this->MinorTickOffset);

      canvas.AddLine(xs,ys, xe,ye, 1.0, this->Color);
    }
  }

  for (unsigned int i=0; i<nmajor; ++i)
  {
    this->Labels[i]->Render(camera, worldAnnotator, canvas);
  }
}


}
} // namespace vtkm::rendering
