/***************************** LICENSE START ***********************************

 Copyright 2015 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvQProfileView.h"

#include <QDebug>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QMouseEvent>
#include <QPainter>

#include "MvProfileData.h"

#include <math.h>

//====================================
//  MvQNodetem
//====================================

MvQNodeItem::MvQNodeItem(MvQProfileItem *prof,bool editable,float yPos) :
  prof_(prof),
  editable_(editable),
  yPos_(yPos)
{	
  	setFlag(ItemSendsGeometryChanges);
    #ifdef METVIEW_QT5		
	    setAcceptHoverEvents(true);
    #else
	    setAcceptsHoverEvents(true);
    #endif
 	setZValue(-1);
	
	if(editable_)   
	{
	  	idleBrush_=QBrush(QColor(Qt::red));
		hoverBrush_=QBrush(QColor(255,205,205));
		moveBrush_=hoverBrush_;
		brush_=idleBrush_;
		
		idlePen_=QPen(Qt::NoPen);
		hoverPen_=QPen(Qt::black);
		movePen_=QPen(Qt::black);
		pen_=idlePen_;		
	}
	else
	{
	  	idleBrush_=QBrush(QColor(Qt::blue));
		hoverBrush_=QBrush(QColor(205,255,205));
		moveBrush_=hoverBrush_;
		brush_=idleBrush_;
		
		idlePen_=QPen(Qt::NoPen);
		hoverPen_=QPen(Qt::black);
		movePen_=QPen(Qt::black);
		pen_=idlePen_;				
	}
	
	idleSize_=6;
	moveSize_=10;
	hoverSize_=10;
	size_=idleSize_;
	 	
}  

MvQNodeItem::~MvQNodeItem()
{
}  

void MvQNodeItem::addEdge(MvQEdgeItem *edge)
{
     	edges_ << edge;
     	edge->adjust();
}

QRectF MvQNodeItem::boundingRect() const
{
	qreal adjust = 2;
     	return QRectF(-size_/2. - adjust, -size_/2. - adjust,
                   size_ + adjust, size_ + adjust);
}

void MvQNodeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget *)
{
     painter->save();
     
     painter->setPen(pen_);
     painter->setBrush(brush_);
     painter->drawEllipse(-size_/2., -size_/2., size_, size_);
     
     painter->restore();
}

QVariant MvQNodeItem::itemChange(GraphicsItemChange change, const QVariant &value)
 {
     	switch(change) 
     	{
     	case ItemPositionHasChanged:
       		foreach (MvQEdgeItem *edge, edges_)
             		edge->adjust();  
         	//prof_->nodeMoved(this);
         	break;
    	default:
         	break;
     	}

     	return QGraphicsItem::itemChange(change, value);
}

void MvQNodeItem::mousePressEvent(QGraphicsSceneMouseEvent */*event*/)
{
     	if(editable_)
	{  	
	  	pen_=movePen_;
		brush_=moveBrush_;
		
		prepareGeometryChange();
		size_=moveSize_;
	}
	
     	//QGraphicsItem::mousePressEvent(event);
}

void MvQNodeItem::mouseReleaseEvent(QGraphicsSceneMouseEvent */*event*/)
{	
	if(editable_)
	{  
		prof_->nodeMoved(this);
		pen_=idlePen_;
		brush_=idleBrush_;
		
		prepareGeometryChange();
		size_=idleSize_;
	}	
     	//QGraphicsItem::mouseReleaseEvent(event);
}

void MvQNodeItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
	if(editable_)
	{  
		//We keep the node on a fixed level!
  		QPointF pp=mapToParent(event->pos());
  		setPos(QPointF(pp.x(),yPos_));	
  		pen_=movePen_;
		brush_=moveBrush_;
		update();
	}	
     	//QGraphicsItem::mouseMoveEvent(event);
}

void MvQNodeItem::hoverEnterEvent(QGraphicsSceneHoverEvent */*event*/)
{
	pen_=hoverPen_;
	brush_=hoverBrush_;
	
	prepareGeometryChange();
	size_=hoverSize_;	
}

void MvQNodeItem::hoverLeaveEvent(QGraphicsSceneHoverEvent */*event*/)
{
	pen_=idlePen_;
	brush_=idleBrush_;
	
	prepareGeometryChange();
	size_=idleSize_;
}

//====================================
//  MvQEdgeItem
//====================================

MvQEdgeItem::MvQEdgeItem(MvQNodeItem* fromNode,MvQNodeItem* toNode) :
  fromNode_(fromNode),
  toNode_(toNode)
{
	if(fromNode->editable())   
     	{	
    		pen_=QPen(Qt::red, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
	}
	else
	{
	  	pen_=QPen(Qt::blue, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
	}
	
        setAcceptedMouseButtons(0);
	fromNode_->addEdge(this);
        toNode_->addEdge(this);
	adjust(); 
}

void MvQEdgeItem::adjust()
{
     if (!fromNode_ || ! toNode_)     
         return;

     QLineF line(mapFromItem(fromNode_, 0, 0), mapFromItem(toNode_, 0, 0));
     
     qreal length=line.length();

     prepareGeometryChange();

     fromPoint_ = toPoint_ = line.p1();
     
     if (length > qreal(6.)) 
     {
         fromPoint_ = line.p1();
         toPoint_ = line.p2();
     } 
     else 
     {
         fromPoint_ = toPoint_ = line.p1();
     }     
}

QRectF MvQEdgeItem::boundingRect() const
{
     if (!fromNode_ || ! toNode_)
         return QRectF();
     
     qreal penWidth = 1;
     qreal extra=penWidth;
     
     return QRectF(fromPoint_, QSizeF(toPoint_.x() - fromPoint_.x(),
                                       toPoint_.y() - fromPoint_.y()))
         .normalized()
         .adjusted(-extra, -extra, extra, extra);
}

void MvQEdgeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *,QWidget*)
{	
	QLineF line(fromPoint_, toPoint_);
    	if(qFuzzyCompare(line.length(), qreal(0.)))
        	return;
    
     	painter->save();
	painter->setPen(pen_);
     	painter->drawLine(line);
	painter->restore();
}  


//====================================
//  MvQProfileItem
//====================================

MvQProfileItem::MvQProfileItem(MvQProfileView *view,MvProfileData *data,bool editable,int editRadius, 
			        int firstIndex, int lastIndex, QSize size,
			        bool setMinMax, float valMin, float valMax) :			      			      
   view_(view),
   data_(data), 
   zeroLine_(false),
   minXSize_(300),
   minYSize_(500),
   editable_(editable),
   editRadius_(editRadius),
   firstIndex_(firstIndex),
   lastIndex_(lastIndex),
   subPlot_(false),
   presetMinMax_(setMinMax),
   presetMin_(valMin),
   presetMax_(valMax),
   pen_(Qt::black),
   gridPen_(QColor(200,200,200))
{	  
  	if(!data_)
	{  
	  	setEnabled(false);
		return;
	}
  
  	if(firstIndex_ < 0 || firstIndex_ >= data_->count())
		firstIndex_=0;
	
	if(firstIndex_ >= lastIndex_ || lastIndex_ >= data_->count())
  		lastIndex_=data_->count()-1;
			
  	initFrame(size);
	adjustFrame();
	
	for(int i=0; i < data_->count(); i++)
	{
	  	float val=data_->value(i);
		float yp=(i-firstIndex_)*yRatio_;
		MvQNodeItem *node=new MvQNodeItem(this,editable,yp);
		node->setParentItem(this);
		node->setPos((val-frameXMin_)*xRatio_,yp);
		if(editable)
		{
			node->setFlag(ItemIsMovable);
		}
	
		nodes_ << node;
	}
	
	for(int i=0; i < data_->count()-1; i++)
	{
	  	MvQEdgeItem *edge=new MvQEdgeItem(nodes_[i],nodes_[i+1]);
		edge->setParentItem(this);
		edges_ << edge;
	} 
	
	
	view->scene()->addItem(this);
	
	adjustData();
	
}

MvQProfileItem::~MvQProfileItem()
{
	if(data_)
	  	delete data_;
}  

void MvQProfileItem::setStep(int step) 
{	  
	step_=step;
	
	if(!isEnabled())
	  	return;
	
	adjustFrame();
	adjustData();
	update();
}

void MvQProfileItem::adjustFrame()
{
	//Min max
	float valMin, valMax;
	
	if(presetMinMax_)
	{
	  	valMin=presetMin_;
		valMax=presetMax_;
	}
	else
	{  
		if(data_->isRangeSet())
		{
			valMin=data_->rangeMin();
			valMax=data_->rangeMax();
		}
		else	
			data_->valueRange(firstIndex_,lastIndex_,valMin,valMax);
	}
	
	//Find a nice plot range
	float valRange=valMax-valMin;
	
	if(valMin < 0 && valMax > 0)
	{
		zeroLine_=true;  	
	}
	
	frameXMin_=0.;
	frameXMax_=0.;
	
	QFont font;
	QFontMetrics fm(font);
	int twMax=fm.width(QString::number(valMax));
	int twMin=fm.width(QString::number(valMin));
	int textWidth=(twMin < twMax)?twMax:twMin;
	
	if(valRange > 0)
	{
	  	int digits=static_cast<int>(log10(valRange)); 
		tickXStep_=pow(10.,digits);
		if(valRange/tickXStep_ < 3)
		{
		  	tickXStep_=pow(10.,digits-1);
		}	
	}
	else if(fabs(valMin) > 0.0000000001  && fabs(valMin) < 1000000000.)
	{
	  	 int digits=static_cast<int>(log10(fabs(valMin))); 
	     tickXStep_=pow(10.,digits);
		
         if(fabs(valMin/tickXStep_) < 3)
		 {
		  	tickXStep_=pow(10.,digits-1);
		 }		         
	}  	
	else
	{
	  	tickXStep_=1;
	}
	
	//We need to ensure that tickXStep_ is greater than 0!!!
	if(tickXStep_ <= 0)
        tickXStep_=1.;
	
	tickXLabelStep_=tickXStep_;
	tickXLabelStepOffset_=0;
	
    //Because tickXStep_ alwasy greater than 0 these two values will always be different!!!
	frameXMin_=static_cast<int>((valMin-tickXStep_-tickXStep_/1000.)/tickXStep_)*tickXStep_;
	frameXMax_=static_cast<int>((valMax+tickXStep_+tickXStep_/1000.)/tickXStep_)*tickXStep_;
	
    //So this division can always be made!!! 
	xRatio_=frameRect_.width()/(frameXMax_-frameXMin_);
    
	//Adjustment
	if(xRatio_*tickXStep_ < textWidth)
	{
	 	tickXLabelStep_*=2;
		int labelFactor=static_cast<int>(round(frameXMin_/tickXStep_));
		if(labelFactor % 2 != 0)		
			tickXLabelStepOffset_=1;
	}
	
	if(lastIndex_ != firstIndex_)
		yRatio_=frameRect_.height()/static_cast<float>(lastIndex_-firstIndex_);
	else
	  	yRatio_=frameRect_.height();
}	
	
	
QRectF MvQProfileItem::boundingRect() const
{
	return bRect_;
}

void MvQProfileItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *,QWidget*)
{	
	painter->save();
  
  	painter->fillRect(bRect_,Qt::white);
		
	QFont font;
	QFontMetrics fm(font);
		
	painter->setPen(pen_);
	
	//Title
	if(!subPlot_)	
	{
	  	QRectF titleRect(frameRect_.width()/2.-150,frameRect_.top()-70,300,40);	
		QString editableText=(editable_==true)?"Editable":"";
		painter->drawText(titleRect,Qt::AlignCenter,
			  "Parameter: " + QString::fromStdString(data_->name()) + 
	                 " [" + QString::fromStdString(data_->units()) + "]\n" +
	                 " Step: " + QString::fromStdString(data_->stepString()) + 
	                  "\n" + editableText);
	}
	/*else
	{
	  	QRectF titleRect(frameRect_.width()/2.-150,frameRect_.top()-50,300,40);	
		painter->drawText(titleRect,Qt::AlignCenter,
			  "Parameter: " + QString::fromStdString(data_->name()) + 
	                 " [" + QString::fromStdString(data_->units()) + "]");  
	} */ 
	
	
	//Render out of normal range 
	if(data_->isRangeSet())
	{
		float valMin=data_->rangeMin();
		float valMax=data_->rangeMax();
	
		if(frameXMin_ < valMin)
		{			  
			float xp=(valMin-frameXMin_)*xRatio_;			
			painter->fillRect(0,frameRect_.top(),xp,frameRect_.bottom(),QBrush(QColor(255,0,0,50)));
		}
		if(frameXMax_ > valMax)
		{
		  	float xp=(valMax-frameXMin_)*xRatio_;
			float xp1=(frameXMax_-frameXMin_)*xRatio_;
			painter->fillRect(xp,frameRect_.top(),xp1-xp,frameRect_.bottom(),QBrush(QColor(255,0,0,50)));
		}
	}	
	
	//Dash pattern for the grid
	//QVector<qreal> dashes;
	//dashes << 1 << 8;
	//gridPen.setDashPattern(dashes);
	
	//Lines
	//X axis - top + bottom
	for(float xv=frameXMin_; xv <= frameXMax_; xv+=tickXStep_)
	{
	  	float xp=(xv-frameXMin_)*xRatio_;
	  	painter->drawLine(xp,frameRect_.top(),xp,frameRect_.top()-6.);
		painter->drawLine(xp,frameRect_.bottom(),xp,frameRect_.bottom()+6.);
		
		//grid		
		if(firstIndex_ != lastIndex_ && xv != frameXMin_ && xv != frameXMax_)
		{  
			painter->setPen(gridPen_);
			painter->drawLine(xp,frameRect_.top(),xp,frameRect_.bottom());
			painter->setPen(pen_);
		}
		
		//text
		//int xpText=xp-fm.width(QString::number(xv))/2;
		//painter->drawText(QPointF(xpText,frameRect_.bottom()+10+fm.ascent()),QString::number(xv));
		
		//if(!subPlot_)
		//	painter->drawText(QPointF(xpText,frameRect_.top()-10-fm.descent()),QString::number(xv));
	}	
	
	//Text
	//X axis - top + bottom
	for(float xv=frameXMin_+tickXLabelStepOffset_*tickXStep_; xv <= frameXMax_; xv+=tickXLabelStep_)
	{
	  	float xp=(xv-frameXMin_)*xRatio_;
	  
		//text
		int xpText=xp-fm.width(QString::number(xv))/2;
		painter->drawText(QPointF(xpText,frameRect_.bottom()+10+fm.ascent()),QString::number(xv));
		
		if(!subPlot_)
			painter->drawText(QPointF(xpText,frameRect_.top()-10-fm.descent()),QString::number(xv));
	}	
	
	
	float dy=frameRect_.height()/(1+lastIndex_-firstIndex_);
	int stepY=10;
	if(dy > 15) stepY=1;
	else if(dy*2 > 15) stepY=2;
	else if(dy*5 > 15) stepY=5;
	else stepY=10;
	
	if(lastIndex_-firstIndex_+ 1 < 6)
	 	stepY=1; 
	
	//Right axis
	if(data_->auxLevelDefined())
	{  
		for(int i=lastIndex_; i >=firstIndex_; i-=stepY)
		{
			float xv=static_cast<float>(floor(data_->auxLevel(i)/100.));
			
	  		float xp=frameRect_.width();
			float yp=frameRect_.top()+(i-firstIndex_)*yRatio_;
			painter->drawLine(xp,yp,xp+6.,yp);
		
			//Label
			int ypText=yp+fm.ascent()/2;
			painter->drawText(QPointF(xp+10,ypText),QString::number(xv));	
		}
		
		//Right axis title
		painter->save();
		painter->translate(frameRect_.width()+10+fm.width("1000")+10+fm.ascent(),frameRect_.center().y());
		painter->rotate(-90);		
		QString auxTitle=QString::fromStdString(data_->auxLevelName()) + " (" + QString::fromStdString(data_->auxLevelUnits()) + ")";
			painter->drawText(-fm.width(auxTitle)/2,0,auxTitle);
		
		painter->restore();
	}
	
	if(lastIndex_ != firstIndex_)
	{
		//Left axis
		for(int i=lastIndex_; i >=firstIndex_; i-=stepY)
		{
			float xv=data_->level(i);
	  		float xp=0;
			float yp=frameRect_.top()+(i-firstIndex_)*yRatio_;
			painter->drawLine(xp,yp,xp-6.,yp);
		
			//grid
			painter->setPen(gridPen_);
			painter->drawLine(xp,yp,xp+frameRect_.width(),yp);
			painter->setPen(pen_);
			
			
			int ypText=yp+fm.ascent()/2;
			int xpText=xp-10-fm.width(QString::number(xv));
			painter->drawText(QPointF(xpText,ypText),QString::number(xv));
		}  
	}
	
	//Left axis title
	painter->save();
	painter->translate(-10-fm.width("100")-10,frameRect_.center().y());
	painter->rotate(-90);
	QString levTitle;
	if(!data_->levelUnits().empty())
	{  
		levTitle=QString::fromStdString(data_->levelName()) + " (" + QString::fromStdString(data_->levelUnits()) + ")";
	}
	else
	{
		levTitle=QString::fromStdString(data_->levelName());  
	}  
	painter->drawText(-fm.width(levTitle)/2,0,levTitle);
	painter->restore();
		
	painter->setRenderHint(QPainter::Antialiasing,false);
	
	// Zero line
	if(zeroLine_)
	{
		float xp=(0.-frameXMin_)*xRatio_;
		painter->drawLine(xp,frameRect_.top(),xp,frameRect_.bottom());
	}
	
	//Frame
	
	if(firstIndex_ != lastIndex_)
		painter->drawRect(frameRect_);
	else
	  	painter->drawLine(0,frameRect_.top(),frameRect_.width(),frameRect_.top());
	
	
	painter->restore();
}
	
bool MvQProfileItem::updateValue(const MvProfileChange& ch)
{	
  	if(data_->acceptChange(ch))
	{
		int index=ch.level();
	  	float val=data_->value(index);
		nodes_.at(index)->setPos((val-frameXMin_)*xRatio_,frameRect_.top()+(index-firstIndex_)*yRatio_);  
				
		//See if the coordinate system needs to be adjusted to the data value range
		if(val < frameXMin_ || val > frameXMax_)
		  	view_->adjustValueRange();
		else  
		  	checkValueRange();
		
		return true;
	}
	return false;
}

void MvQProfileItem::reload()
{
	prepareGeometryChange();
	adjustFrame();
	adjustData();		
	update();
} 

void MvQProfileItem::nodeMoved(MvQNodeItem *node)
{
	int index=nodes_.indexOf(node);
	if(index != -1)
	{
	  	float val=data_->value(index);		
		if(fabs((val-frameXMin_)*xRatio_-node->pos().x()) > 0.1)
		{  	  
	  		float f=frameXMin_+node->pos().x()/xRatio_;
			//if(!data_->fitToRange(f))
			//{
			//	data_->setValue(index,f); 
			//	nodes_.at(index)->setPos((f-frameXMin_)*xRatio_,(index-firstIndex_)*yRatio_); 
			//}
			//else
			//{
			  	data_->setValue(index,f);
			//} 
			
			if(f < frameXMin_ || f > frameXMax_)
			{
			  	view_->adjustValueRange();
			}	
		}	
	}
}	

void MvQProfileItem::initFrame(QSize size)
{
  	float w=size.width();
	if(w < minXSize_) w=minXSize_;
  
        float h=size.height();
	if(h < minYSize_) h=minYSize_;
   	
  	frameRect_=QRectF(0,0,w-150,h-120);
	bRect_= frameRect_.adjusted(-60,-80,90,30);
}	

void MvQProfileItem::initFrame(QRectF r)
{
  	frameRect_=r;
	if(subPlot_)	
		bRect_= frameRect_.adjusted(-60,-30,90,30);
	else
	  	bRect_= frameRect_.adjusted(-60,-80,90,30);
}	


void MvQProfileItem::adjustData()
{
	if(data_)
	{
		for(int i=0; i < data_->count(); i++)
		{
	  		float val=data_->value(i);
			float yp=frameRect_.top()+(i-firstIndex_)*yRatio_;
			
			if(i < firstIndex_)
			{  
			 	if(nodes_.at(i)->scene() != 0)
				{
			  		scene()->removeItem(nodes_.at(i));
					nodes_.at(i)->setVisible(false);							
					//qDebug() << "remove node" << i << nodes_.at(i)->scene();
				}	
				
				if(i < edges_.count() && edges_.at(i)->scene())
				{	
				  	scene()->removeItem(edges_.at(i));
					edges_.at(i)->setVisible(false);
					//qDebug() << "  remove edge " << i << edges_.at(i)->scene(); 
				}
				
				if(i > 0 && edges_.at(i-1)->scene())
				{
				  	scene()->removeItem(edges_.at(i-1)); 
					edges_.at(i-1)->setVisible(false);
					//qDebug() << "  remove edge " << i-1 << edges_.at(i-1)->scene(); 
				}	
				
			}			
			else if(i > lastIndex_)
			{  
			 	if(nodes_.at(i)->scene() != 0)
				{
			  		scene()->removeItem(nodes_.at(i));
					nodes_.at(i)->setVisible(false);							
					//qDebug() << "remove node" << i << nodes_.at(i)->scene();
				}	
				
				if(i > 0 && edges_.at(i-1)->scene())
				{
				  	scene()->removeItem(edges_.at(i-1)); 
					edges_.at(i-1)->setVisible(false);
					//qDebug() << "  remove edge " << i-1 << edges_.at(i-1)->scene(); 
				}	
				
				/*if(i < edges_.count() && edges_.at(i)->scene())
				{	
				  	scene()->removeItem(edges_.at(i));
					edges_.at(i)->setVisible(false);
					qDebug() << "  remove edge " << i << edges_.at(i)->scene(); 
				}*/				
			}			
			else if(nodes_.at(i)->scene() == 0)
			{				
		  		//qDebug() << "add node" << i << nodes_.at(i)->scene();; 
		  		
		  		nodes_.at(i)->setParentItem(this);
				nodes_.at(i)->setVisible(true);
				
				if(i < edges_.count() && !edges_.at(i)->scene() && nodes_.at(i+1)->scene() != 0)
				{
				  	edges_.at(i)->setParentItem(this);
					edges_.at(i)->setVisible(true);
					//qDebug() << "    add edge" << i << edges_.at(i)->scene();; 
				}
				
				if(i > 1 && !edges_.at(i-1)->scene() && nodes_.at(i-1)->scene() != 0)
				{
				  	edges_.at(i-1)->setParentItem(this);
					edges_.at(i-1)->setVisible(true);
					//qDebug() << "    add edge" << i << edges_.at(i-1)->scene();; 
				}
				
			}	
		  			  	
			nodes_.at(i)->setPos((val-frameXMin_)*xRatio_,yp);
			nodes_.at(i)->setYPos(yp);	
		}
	}	
}	
		
void MvQProfileItem::adjustSize(QSize size)
{
	prepareGeometryChange();
	
	initFrame(size);	
	adjustFrame();
	adjustData();
}  

void MvQProfileItem::adjustSize(QRectF r)
{
	prepareGeometryChange();
	
	initFrame(r);	
	adjustFrame();
	adjustData();
}  


void MvQProfileItem::setLevelRange(int firstIndex,int lastIndex)
{
	firstIndex_=firstIndex;
	lastIndex_=lastIndex;
  
  	if(firstIndex_ < 0 || firstIndex_ >= data_->count())
		firstIndex_=0;
	
	if(firstIndex_ >= lastIndex_ || lastIndex_ >= data_->count())
  		lastIndex_=data_->count()-1;
  
	prepareGeometryChange();
	adjustFrame();
	adjustData();		
	update();
}  


void MvQProfileItem::setLevelRange(int firstIndex,int lastIndex, float valMin, float valMax)
{
	if(presetMinMax_)
	{
	  	presetMin_=valMin;
		presetMax_=valMax;
	}	
  
  	setLevelRange(firstIndex,lastIndex);
}  


void MvQProfileItem::setValueRange(float valMin, float valMax)
{
	if(presetMinMax_)
	{
	  	presetMin_=valMin;
		presetMax_=valMax;
		
		prepareGeometryChange();
		adjustFrame();
		adjustData();		
		update();
	}
} 

void MvQProfileItem::setEditRadius(int rad)
{
	editRadius_=rad;
}  

void MvQProfileItem::valueRange(int firstIndex,int lastIndex,float &valMin,float &valMax)
{  	
	if(data_->isRangeSet())
	{
		valMin=data_->rangeMin();
		valMax=data_->rangeMax();
	}
	else	
	{		  
		data_->valueRange(firstIndex,lastIndex,valMin,valMax);
	}
}	
	
	
void MvQProfileItem::valueRange(float &valMin,float &valMax)
{  	
	if(data_->isRangeSet())
	{
		valMin=data_->rangeMin();
		valMax=data_->rangeMax();
	}
	else	
	{		  
		data_->valueRange(valMin,valMax);
	}
}

void MvQProfileItem::checkValueRange()
{
	//See if the coordinate system needs to be adjusted to the data value range
	if(!presetMinMax_ && !data_->isRangeSet())
	{
		float valMin, valMax;
		data_->valueRange(firstIndex_,lastIndex_,valMin,valMax);
		valMax=(fabs(valMax) > fabs(valMin))?fabs(valMax):fabs(valMin);
		float frameMax=(fabs(frameXMax_) > fabs(frameXMin_))?fabs(frameXMax_):fabs(frameXMin_);
			
		if(valMax > 0.0000000001 && valMax < frameMax/100.)
			  view_->adjustValueRange();
	}
}	
				
bool MvQProfileItem::cursorData(QPointF scenePos,QString &txt)
{
	QPointF pos=mapFromScene(scenePos);
	
	float xv=frameXMin_+pos.x()/xRatio_;
	float yv=(pos.y()-frameRect_.top())/yRatio_+firstIndex_+1.5;
	
	if(xv >= frameXMin_ && xv <= frameXMax_ &&
	   yv >= firstIndex_ && yv <=lastIndex_+1.5)
	{
	  	txt=" <b>Level:</b> " + QString::number(static_cast<int>(yv)) +"  <b>Value:</b> " +  QString::number(xv);
		
	  	int lev=static_cast<int>(yv)-1;
		if(lev >=0 && lev < data_->count())
		{
	  		float rv=data_->value(lev);
			float rp=(rv-frameXMin_)*xRatio_;
			if(fabs(rp-pos.x()) < 10)
			{			 		 
			  	if(editable_)  
			  		txt+=" <b>Data value:</b> <font color=#ff0000>" + QString::number(rv) + "</font>";
				else
				  	txt+=" <b>Data value:</b> <font color=#0000ff>" + QString::number(rv) + "</font>";
 			}
		}	
		
		return true;
	}
	
	return false;
}	

//==============================================
// MvQProfileView
//==============================================

MvQProfileView::MvQProfileView(QWidget *parent) : 
    QGraphicsView(parent)
{
	setRenderHints(QPainter::Antialiasing);
	setBackgroundBrush(QColor(125,124,123));
	setAlignment(Qt::AlignCenter); 
	
	scene_=new QGraphicsScene(this);
	setScene(scene_);
}

void MvQProfileView::setProfile(QList<MvProfileData*> profData, bool editable,int startIndex,int endIndex)
{
	QList<MvQProfileItem*> itemsToBeDeleted;
  
  	foreach(MvQProfileItem *item,prof_)
	{
	  	scene_->removeItem(item);
		itemsToBeDeleted << item;
	}	
    	prof_.clear();
    	//profWeight_.clear();
    	
  	QSize size=maximumViewportSize();	
	size-=QSize(10,10);

	///Min max
	bool setMinMax=false;
	float valMin=999999, valMax=-9999999;
	if(profData.count() > 1)
	{
		setMinMax=true;
		for(int i=0; i < profData.count(); i++)
		{  
			if(profData[i]->isRangeSet())
			{
				valMin=profData[i]->rangeMin();
				valMax=profData[i]->rangeMax();
				break;
			}
			else	
			{
		  		float vmin, vmax;
		  		profData[i]->valueRange(0,profData[i]->count()-1,vmin,vmax);
				if(vmin < valMin) valMin=vmin;
				if(vmax > valMax) valMax=vmax;
			}
		}	
	}	
	
	//Create plot items
	if(profData.count() > 0)
	{
	  	prof_ << new MvQProfileItem(this,profData[0],editable,0,startIndex,endIndex,size,
					    setMinMax,valMin,valMax); 
					    
		for(int i=1; i < profData.count(); i++)
		{	
			prof_ << new MvQProfileItem(this,profData[i],editable,0,0,profData[i]->count()-1,size,
						    setMinMax,valMin,valMax);
			prof_.back()->setSubPlot(true);
		}
	}

	adjustSize();
	
	foreach(MvQProfileItem *item,itemsToBeDeleted)
	{
	  	delete item;
	}	
}	

void MvQProfileView::update(const MvProfileChange& item)
{
  	foreach(MvQProfileItem *p, prof_)
	{
	  	if(p && p->updateValue(item))
			  return;
	}	
}	

void MvQProfileView::reload()
{
	foreach(MvQProfileItem *item, prof_)
	{
	  	if(item)
	  		item->reload();
	}	
}

void MvQProfileView::mouseMoveEvent(QMouseEvent *event)
{		
  	QGraphicsView::mouseMoveEvent(event);	
	
	QString txt=tr(" Cursor out of plot!");
	
	foreach(MvQProfileItem *p, prof_)
		if(p->cursorData(mapToScene(event->pos()),txt))
			break;
		
	emit cursorData(txt);
}

void MvQProfileView::resizeEvent(QResizeEvent *event)
{
	QGraphicsView::resizeEvent(event);
	adjustSize();
}

void MvQProfileView::adjustSize()
{
	QSize size=maximumViewportSize();
	size-=QSize(10,10);

	//Needs to be improved
	if(prof_.count() > 1)
	{
		int h=0;
	  	for(int i=1; i < prof_.count(); i++)
		{
	  		if(prof_[i]->levelNum() == 1)
			{
				h+=60+0;
			}
			else if(prof_[i]->levelNum() < 6)
			{
			  	h+=60+60;
			}
			else
				h+=60+100;
		}	
		  
	  	QSize firstSize(size.width(),size.height()-h);
		prof_[0]->adjustSize(firstSize);
	
		QRectF r=prof_[0]->frameRect();
		for(int i=1; i < prof_.count(); i++)
		{
			if(prof_[i]->levelNum() == 1)
			{
			  	r=QRectF(0,r.bottom()+60,r.width(),0);
			}
			else if(prof_[i]->levelNum() < 6)
			{
				r=QRectF(0,r.bottom()+60,r.width(),60);
			}
			else if(prof_[i]->levelNum() < 6)
			{
				r=QRectF(0,r.bottom()+60,r.width(),100);
			}
			prof_[i]->adjustSize(r);	
		}
	}
	else if(prof_.count() > 0 && prof_[0])
	{
	  	prof_[0]->adjustSize(size);
	}	
	
	//Set the scenerect
	if(prof_.count() > 0)
	{
		QRectF bb=prof_[0]->boundingRect();
		for(int i=1; i < prof_.count(); i++)
		{
			bb=bb.united(prof_[i]->boundingRect());
		}
		scene_->setSceneRect(bb);
	}			  	  
}

void MvQProfileView::adjustValueRange()
{
	if(prof_.count() > 0 && prof_[0])
  	{ 
		float valMin=999999, valMax=-9999999;
		for(int i=0; i < prof_.count(); i++)
		{
			float vmin,vmax;
			if(i==0)
				  prof_[i]->valueRange(prof_[i]->firstIndex(),prof_[i]->lastIndex(),vmin,vmax);
			else
				  prof_[i]->valueRange(vmin,vmax);
				  				 
	  		if(vmin < valMin) valMin=vmin;
			if(vmax > valMax) valMax=vmax;
		}
	
		if(prof_.count() ==1)
		{
		  	prof_[0]->reload();
		}
		else
		{  
			for(int i=0; i < prof_.count(); i++)
			{
				  prof_[i]->setValueRange(valMin,valMax);
			}	
		}	
	}		
}

void MvQProfileView::setLevelRange(int startIndex,int endIndex)
{
	if(prof_.count() > 0 && prof_[0])
  	{ 
		if(prof_.count() > 1)
		{
			 float valMin=999999, valMax=-9999999;
			 for(int i=0; i < prof_.count(); i++)
			 {
			 	float vmin,vmax;
				if(i==0)
				  	prof_[i]->valueRange(startIndex, endIndex,vmin,vmax);
				else
				  	prof_[i]->valueRange(vmin,vmax);
				  
				 
	  			if(vmin < valMin) valMin=vmin;
				if(vmax > valMax) valMax=vmax;
			 }
			 
			 prof_[0]->setLevelRange(startIndex,endIndex,valMin,valMax);
			 for(int i=1; i < prof_.count(); i++)
			 {
			   	prof_[i]->setValueRange(valMin,valMax);
			 }	
		}
		else
		{  
	  		prof_[0]->setLevelRange(startIndex,endIndex);
		}	
	}	
}

void MvQProfileView::setEditRadius(int rad)
{
  	foreach(MvQProfileItem *item, prof_)
	{
	  	if(item)
	  		item->setEditRadius(rad);
	}	
}
