text: /*
   * (C) Copyright 1996-2016 ECMWF.
   *
   * This software is licensed under the terms of the Apache Licence Version 2.0
   * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
   * In applying this licence, ECMWF does not waive the privileges and immunities
   * granted to it by virtue of its status as an intergovernmental organisation nor
   * does it submit to any jurisdiction.
   */
  
  /*! \file SymbolPlotting.cc
      \brief Implementation of the Template class SymbolPlotting.
  
      Magics Team - ECMWF 2004
  
      Started: Mon 19-Jan-2004
  
      Changes:
  
  */
  
  #include "SymbolPlotting.h"
  #include "Factory.h"
  
  #include "MagicsFormat.h"
  #include "ProgressObject.h"
  
  #include "LegendVisitor.h"
  
  using namespace magics;
  
  
  SymbolPlotting::SymbolPlotting() {}
  
  SymbolPlotting::~SymbolPlotting() {}
  
  /*!
   Class information are given to the output-stream.
  */
  void SymbolPlotting::print(ostream& out) const {
      out << "SymbolPlotting[";
      SymbolPlottingAttributes::print(out);
      out << "]";
  }
  
  double SymbolPlotting::height(const Transformation& transformation, double height) {
      if (scaling_method_ == false)
          return height;
  
      // get Area !
  
      return transformation.ratio() * scaling_level_0_ * scaling_factor_;
  }
  
  void SymbolPlotting::getReady(const LegendVisitor& legend) { legend_only_ = legend.only_; }
  
  void SymbolPlotting::operator()(const PaperPoint& point, BasicGraphicsObjectContainer& out) const {
      try {
          if (point.missing())
              return;
          if ((*mode_).accept(point.value()) == false)
              return;
  
          SymbolProperties properties = (*mode_)(point.value());
  
          string value;
  
          if (magCompare(type_, "number") || magCompare(type_, "both")) {
              ostringstream nice;
  
              nice << MagicsFormat(format_, point.value());
              if (point.name() != "")
                  nice << "[" << point.name() << "]";
              value = nice.str();
          }
  
  
          if (magCompare(type_, "marker_text")) {
              value = point.name();
              if (point.name() == "")
                  value = "_FORCE_EMPTY_TEXT_";
          }
  
  
          map<SymbolProperties, Symbol*>::const_iterator symb = symbols_.find(properties);
          if (symb != symbols_.end()) {
              symb->second->push_back(point, value);
              return;
          }
  
  
          Symbol* symbol = properties.symbol(type_);
  
  
          symbols_[properties] = symbol;
  
          symbol->push_back(point, value);
      }
      catch (...) {
      }
  }
  
  struct Print {
      void operator()(const UserPoint& point) { MagLog::debug() << point << "\n"; }
  };
  
  
  struct SortHelper {
      SortHelper() {}
      ~SortHelper() {}
      MAGICS_NO_EXPORT bool operator()(const Symbol* first, const Symbol* second) {
          return first->size() > second->size();
      }
  };
  
  
  void SymbolPlotting::operator()(Data& data, BasicGraphicsObjectContainer& out) {
      mode_->parent(this);
      mode_->prepare();
      symbols_.clear();
      vector<string> check;
      check.push_back("text");
      check.push_back("number");
      check.push_back("marker");
      check.push_back("both");
      check.push_back("marker_text");
  
      bool valid = false;
  
      for (vector<string>::iterator c = check.begin(); c != check.end(); ++c) {
          valid = magCompare(*c, type_);
          if (valid)
              break;
      }
      if (!valid) {
          MagLog::warning() << type_ << " not yet implemented : reset to marker " << endl;
          type_ = "marker";
      }
      mode_->set(type_);
  
  
      try {
          const Transformation& transformation = out.transformation();
  
          // If we need to connect the symbols with a line, we need all the poinst
          // to enable proper clipping of the line! Othewise wee just nedde to get the point
          // from the visible area.
  
          PointsHandler& points = data.points(transformation, connect_);
  
          // Some Mode need to know the min and max of the data, in order to adjust the
          // computation of the levels
          (*mode_).adjust(points.min(), points.max(), scaling_method_, transformation, scaling_factor_);
          if (legend_only_)
              return;
  
          points.setToFirst();
          while (points.more()) {
              PaperPoint xy = transformation(points.current());
              (*this)(xy, out);
  
  
              points.advance();
          }
  
          // WE sort: send the longest one first!
          vector<Symbol*> work;
          for (map<SymbolProperties, Symbol*>::iterator symbol = symbols_.begin(); symbol != symbols_.end(); ++symbol)
              work.push_back(symbol->second);
  
          std::sort(work.begin(), work.end(), SortHelper());
  
          // Now we feed the task...     f
          for (vector<Symbol*>::iterator symbol = work.begin(); symbol != work.end(); ++symbol) {
              if (!(*symbol)->empty()) {
                  (*symbol)->boundingbox(out.transformation().getPCBoundingBox());
                  out.push_back(*symbol);
              }
          }
  
          for (vector<Text*>::iterator text = texts_.begin(); text != texts_.end(); ++text) {
              out.push_back(*text);
          }
      }
      catch (MagicsException&) {
          // do nothing!
      }
  }
  
  void SymbolPlotting::visit(Data& data, LegendVisitor& legend) {
      MagLog::debug() << " SymbolPlotting::visit to create a legend ... "
                      << "\n";
      if (!legend_)
          return;
      (*mode_).visit(data, legend);
  }
  
  void SymbolPlotting::visit(Data& data, HistoVisitor& histo) {
      MagLog::debug() << " SymbolPlotting::visit to create a histogram! ... "
                      << "\n";
  
      mode_->visit(data, histo);
  }
  