/* -*- C++ -*-
   
  This file is part of ViPEC
  Copyright (C) 1991-2000 Johan Rossouw (jrossouw@alcatel.altech.co.za)
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU Library 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 Library General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
*/

#include <GraphView.h>
#include <DrawingFrame.h>
#include <TableFrame.h>
#include <MainWindow.h>
#include <GraphUtils.h>
#include <Strings.h>
#include <Logger.h>

#include <qpopupmenu.h>
#include <qmenubar.h>
#include <qstatusbar.h>
#include <qfont.h>
#include <qfontdialog.h>
#include <qlayout.h>
#include <qmessagebox.h>
#include <qpaintdevicemetrics.h>

#include <stdio.h>
#include <iostream>

using namespace std;

QFont GraphView::titleFont_ = QFont("charter", 14, QFont::Bold );
QFont GraphView::labelFont_ = QFont( "helvetica", 10, QFont::Normal );

QPrinter* GraphView::printer_ = 0;

//----------------------------------------------------------------------------
GraphView::GraphView( GraphViewType viewType, const char* name, WFlags f )
    : QDialog(0, name, FALSE, f),
    frame_(0),
    table_(0),
    viewType_( viewType ),
    viewTitle_("")
{
  setName( name );
  setBackgroundMode( NoBackground );
  resize(400,300);

  printer_ = new QPrinter;

  QVBoxLayout* layout = new QVBoxLayout(this);

  //Init menu
  menuBar_ = new QMenuBar(this, "GraphView menu");
  createMenus();

  layout->addWidget(menuBar_);
  menuBar_->setFixedHeight(menuBar_->height());

  if (viewType == tableView)
    {
      table_ = new TableFrame(*this);
      layout->addWidget( table_ );
    }
  else
    {
      frame_ = new DrawingFrame(*this);
      layout->addWidget( frame_ );
    }

  //Enable mouse tracking
  setMouseTracking(true);

  setDefaults();

  connect(this, SIGNAL(fontChanged()), MainWindow::instance(), SLOT(graphFontChanged()));

}

//----------------------------------------------------------------------------
GraphView::~GraphView()
{
  emptySeries();
  if ( frame_ != 0 )
    {
      delete frame_;
      frame_ = 0;
    }
}

//----------------------------------------------------------------------------
void GraphView::createMenus()
{
  QString fileMenuLabel = Strings::translate( Strings::MenuLabelFile );
  QString saveMenuLabel = Strings::translate( Strings::MenuLabelSave );
  QString viewMenuLabel = Strings::translate( Strings::MenuLabelView );
  QString refreshMenuLabel = Strings::translate( Strings::MenuLabelRefresh );
  QString printMenuLabel = Strings::translate( Strings::MenuLabelPrint );
  QString markersMenuLabel = Strings::translate( Strings::MenuLabelMarkers );
  QString toggleMenuLabel = Strings::translate( Strings::MenuLabelToggle );
  QString fontsMenuLabel = Strings::translate( Strings::MenuLabelFonts );
  QString titleFontMenuLabel = Strings::translate( Strings::MenuLabelTitleFont );
  QString labelFontMenuLabel = Strings::translate( Strings::MenuLabelLabelFont );

  if ( getViewType() == tableView )
    {
      QPopupMenu* menu = new QPopupMenu();
      menuBar().insertItem( fileMenuLabel, menu );
      menu->insertItem( saveMenuLabel, this, SLOT(save()), 0 );
    }

  QPopupMenu* menu1 = new QPopupMenu();
  menuBar().insertItem( viewMenuLabel, menu1 );

  menu1->insertItem( refreshMenuLabel, this, SLOT(reDraw()), 0 );
  menu1->insertItem( printMenuLabel, this, SLOT(print()), 0 );

  if ( getViewType() != tableView )
    {
      QPopupMenu * menu2 = new QPopupMenu();
      menuBar_->insertItem( markersMenuLabel, menu2 );
      menu2->insertItem( toggleMenuLabel, this, SLOT(toggleMarkers()), 0 );

      QPopupMenu* menu3 = new QPopupMenu();
      menuBar_->insertItem( fontsMenuLabel, menu3);
      menu3->insertItem( titleFontMenuLabel, this, SLOT(setTitleFont()), 0 );
      menu3->insertItem( labelFontMenuLabel, this, SLOT(setLabelFont()), 0 );
    }
}

//----------------------------------------------------------------------------
GraphView::GraphViewType GraphView::getViewType() const
  {
    return viewType_;
  }

//----------------------------------------------------------------------------
void GraphView::addSeries(const QString& title, uint size)
{
  seriesMap_.insert( title, DataVector( size ) );
}

//----------------------------------------------------------------------------
void GraphView::addData(const QString& title, TReal x, TReal y, uint size)
{
  bool hasSeries = seriesMap_.contains( QString( title ) );
  if ( !hasSeries )
    {
      addSeries( title, size );
    }
  DataVector& vector = seriesMap_[title];
  vector.addPoint( TComplex( x, y ) );
}

//----------------------------------------------------------------------------
void GraphView::emptySeries()
{
  seriesMap_.clear();
}

//----------------------------------------------------------------------------
bool GraphView::isEmpty()
{
  return ( seriesMap_.count() == 0 );
}

//----------------------------------------------------------------------------
void GraphView::setDefaults()
{
  showMarkers_ = true;
  viewTitle_.sprintf("View Title");
  cursorLabel_ = "Cursor %d:\n\tX=%3.3f\n\tY=%3.3f";
  for (int i=0; i<2; i++)
    {
      showCursor_[i] = false;
    }
}

//----------------------------------------------------------------------------
void GraphView::setName(const char* value)
{
  name_ = value;
  setCaption("ViPEC : " + name_ );
}

//----------------------------------------------------------------------------
const QString& GraphView::getName() const
  {
    return name_;
  }

//----------------------------------------------------------------------------
void GraphView::setTitle(const char* value)
{
  viewTitle_ = value;
  //setCaption("ViPEC : " + viewTitle_);
}

//----------------------------------------------------------------------------
const QString& GraphView::getTitle() const
  {
    return viewTitle_;
  }

//----------------------------------------------------------------------------
QMenuBar& GraphView::menuBar()
{
  ASSERT( menuBar_ != 0 );
  return *menuBar_;
}

//----------------------------------------------------------------------------
void GraphView::setCursorLabel(QString label)
{
  cursorLabel_ = label;
}

//----------------------------------------------------------------------------
bool GraphView::showMarkers()
{
  return showMarkers_;
}

//----------------------------------------------------------------------------
void GraphView::drawCursors(QPainter* p, QRect textRect)
{
  QFont font = getLabelFont(p->device());
  p->setFont( font );

  //Print cursor position
  int xp, yp;
  int dx = (int) floor(10.0*scale_);
  int lineSpacing = 0;
  lineSpacing = p->fontMetrics().lineSpacing();

  int textPos = textRect.y();

  p->setPen(black);
  for (int i=0; i<2; i++)
    if (showCursor_[i])
      {
        TReal x,y;

#ifndef HP_CC

        x = clickedPos_[i].real();
        y = clickedPos_[i].imag();
#else

        x = real(clickedPos_[i]);
        y = imag(clickedPos_[i]);
#endif

        QPoint pos = toClient( x, y );
        xp = pos.x();
        yp = pos.y();

        if (isInsideView(pos))
          {
            GraphUtils::drawCursor(p, xp, yp, dx);

            QString msg;
            msg.sprintf( "%d", i+1 );
            QRect rect = p->fontMetrics().boundingRect(msg);
            QPoint cpos(xp+2,yp-2);
            rect.moveBottomLeft(cpos);
            p->drawText(rect, AlignCenter, msg);

            TComplex coord = transformCoordinates( TComplex(x,y) );
            msg.sprintf(cursorLabel_, i+1,
                        real(coord),
                        imag(coord)
                       );

            xp = textRect.x();
            yp = textPos;
            QRect r(xp, yp, textRect.width(), 3*lineSpacing );
            p->drawText(r, AlignLeft | AlignTop, msg);
            textPos += 3*lineSpacing;
          }
      }
}
//----------------------------------------------------------------------------
void GraphView::save()
{
  //Do nothing
}

//----------------------------------------------------------------------------
void GraphView::print()
{
#ifdef WIN_DEMO
  QMessageBox::warning( this, Strings::LabelApplicationName,
                        "The print feature is disabled in the Windows demo",
                        tr(Strings::LabelOk),
                        0, 0, 0, 0);
#else

  if ( printer_->setup(this) )
    {
      QPainter paint( printer_ );
      print(&paint);
    }
#endif
}

//----------------------------------------------------------------------------
void GraphView::reDraw()
{
  if (frame_)
    {
      frame_->reDraw();
    }
  if (table_)
    {
      table_->reDraw();
    }
}

//----------------------------------------------------------------------------
void GraphView::toggleMarkers()
{
  showMarkers_ = !showMarkers_;
  reDraw();
}

//----------------------------------------------------------------------------
void GraphView::mousePressEvent( QMouseEvent* e )
{
  int index = -1;
  switch (e->button())
    {
    case LeftButton:
      index = 0;
      break;
    case RightButton:
      index = 1;
      break;
    default:
      index = -1;
      break;
    }

  if (index<0)
    return;

  QPoint pos = e->pos();
  clickedPos_[index] = fromClient( pos.x(), pos.y() );  // extract pointer position
  showCursor_[index] = true;
}

//----------------------------------------------------------------------------
void GraphView::mouseMoveEvent( QMouseEvent* e )
{
  int index = -1;
  currentPos_ = e->pos();		// extract pointer position
  switch (e->state())
    {
    case LeftButton:
      index = 0;
      break;
    case RightButton:
      index = 1;
      break;
    default:
      index = -1;
      break;
    }

  if (index<0)
    return;

  QPoint pos = e->pos();
  clickedPos_[index] = fromClient( pos.x(), pos.y() ); // extract pointer position
  showCursor_[index] = true;
}

//----------------------------------------------------------------------------
void GraphView::setTitleFont()
{
  setFont(titleFont_);
}

//----------------------------------------------------------------------------
void GraphView::setLabelFont()
{
  setFont(labelFont_);
}

//----------------------------------------------------------------------------
void GraphView::setFont(QFont& font)
{
  bool ok;
  QFont f = QFontDialog::getFont( &ok, font, this );
  if ( ok )
    {
      font = f;
      emit fontChanged();
    }
}

//----------------------------------------------------------------------------
QFont GraphView::getTitleFont(QPaintDevice* p)
{
  double fontScale = getFontScale(p);
  double fontSize = titleFont_.pointSizeFloat() * scale_ * fontScale;
  QFont font = titleFont_;
  QString message = QString("GraphView::getTitleFont - font pixel size is %1").arg(fontSize);
  Logger::debug(message);
  font.setPointSizeFloat(fontSize);
  return font;
}

//----------------------------------------------------------------------------
QFont GraphView::getLabelFont(QPaintDevice* p)
{
  double fontScale = getFontScale(p);
  double fontSize = labelFont_.pointSizeFloat() * scale_ * fontScale;
  QFont font = labelFont_;
  QString message = QString("GraphView::getLabelFont - font pixel size is %1").arg(fontSize);
  Logger::debug(message);
  font.setPointSizeFloat(fontSize);
  return font;
}

//----------------------------------------------------------------------------
double GraphView::getFontScale(QPaintDevice* p)
{
  double fontScale = 1.0;
  if (p)
    {
      QPaintDeviceMetrics metrics(p);
      fontScale = 76.0 / (double) metrics.logicalDpiX();
      QString message = QString("GraphView::getFontScale - font scale is %1").arg(fontScale);
  	  Logger::debug(message);
    }
  return fontScale;
}
