#include "input_geometry_curves.hpp"

QtInputGeometryCurves::QtInputGeometryCurves(){
  margin=10;
  radius=8;
  min_d=0.01;
  initPoints();
  hbot.setPoints(point,np);
  hbot.compute();
  hsoil.setPoints(&point[np],np);
  hsoil.compute();
}

void
QtInputGeometryCurves::initPoints(){
  for(size_t i=0;i<np;++i){
    double x=double(i)/(np-1);
    point[i].x=x;
    point[i].y=0.7;
    point[i+np].x=x;
    point[i+np].y=0.3;
  }
}

int
QtInputGeometryCurves::get_x(float x,int w){
  return margin+x*w;
}

int
QtInputGeometryCurves::get_y(float y,int h){
  return y*h;
}

void
QtInputGeometryCurves::paintEvent(QPaintEvent* event){
  QPainter painter(this);
  painter.setRenderHint(QPainter::Antialiasing);
  int w=width()-2*margin;
  int h=height();
  // Hbot
  painter.setBrush(Qt::SolidPattern);
  painter.setPen(QColor(102,102,102));
  drawSpline(hbot,painter);
  painter.setPen(QColor(154,77,0));
  drawSpline(hsoil,painter);
  painter.setPen(Qt::black);

  //Control points
  for(size_t i=0;i<2*np;++i){
    Point& P=point[i];
    painter.drawEllipse(get_x(P.x,w)-radius,get_y(P.y,h)-radius,2*radius,2*radius);
  }
}

void
QtInputGeometryCurves::mousePressEvent(QMouseEvent* event){
  int mx=event->x();
  int my=event->y();
  selected=findPoint(mx,my);
}

void
QtInputGeometryCurves::mouseMoveEvent(QMouseEvent* event){
  if(selected<2*np){
    int w=width()-2*margin;
    int h=height();
    float mx=event->x();
    float my=event->y();
    float x=(mx-margin)/w;
    float y=my/h;
    moveSelected(x,y);
    update();
  }
}

void
QtInputGeometryCurves::mouseReleaseEvent(QMouseEvent* event){
  selected=2*np;
}

size_t
QtInputGeometryCurves::findPoint(int x,int y){
  int w=width()-2*margin;
  int h=height();
  for(size_t i=0;i<2*np;++i){
    Point& P=point[i];
    int px=get_x(P.x,w);
    int py=get_y(P.y,h);
    int dx=x-px;
    int dy=y-py;
    int d=dx*dx+dy*dy;
    if(d<=radius*radius) return i;
  }
  return 2*np;
}

void
QtInputGeometryCurves::moveSelected(float x,float y){
  double xp=point[selected].x;
  double yp=point[selected].y;
  if(selected!=0 and selected!=np-1){
    float xmin=point[selected-1].x+min_d;
    float xmax=point[selected+1].x-min_d;
    if(xmin<=x and x<=xmax){
      point[selected].x=x;
    }
  }
  if(0<=y and y<=1){
    point[selected].y=y;
  }
  
  if(selected<np) hbot.compute();
  else hsoil.compute();
  double w=width()-2*margin;
  bool ok=true;
  for(int i=1;i<=w;++i){
    double x=i/w;
    double ybot=hbot(x);
    double ysoil=hsoil(x);
    if(ybot<min_d or ybot>1-min_d or ysoil<min_d or ysoil>1-min_d or ybot<ysoil+min_d){
      point[selected].x=xp;
      point[selected].y=yp;
      if(selected<np) hbot.compute();
      else hsoil.compute();
      return;
    }
  }
}

void
QtInputGeometryCurves::drawSpline(Spline& S,QPainter& painter){
  double w=width()-2*margin;
  double h=height();
  double xp=0;
  double yp=S(0);
  for(int i=1;i<=w;i+=2){
    double x=i/w;
    double y=S(x);
    painter.drawLine(margin+xp*w,yp*h,margin+x*w,y*h);
    xp=x;
    yp=y;
  }
}

void
QtInputGeometryCurves::save(fstream& file){
  for(size_t i=0;i<2*np;++i){
    file.write((char*)&point[i].x,sizeof(double));
    file.write((char*)&point[i].y,sizeof(double));
  }
}

void
QtInputGeometryCurves::load(fstream& file){
  for(size_t i=0;i<2*np;++i){
    file.read((char*)&point[i].x,sizeof(double));
    file.read((char*)&point[i].y,sizeof(double));
  }
  hbot.compute();
  hsoil.compute();
  update();
}
