#include "qt/input_view.hpp"

QtInputView::QtInputView(QtInputGeometry* _input_geometry,Geometry* geometry,InitialState* _initial_state,Source* _source):QtView(geometry){
  input_geometry=_input_geometry;
  initial_state=_initial_state;
  source=_source;
  selected=3*np;
  status=Other;
  initPoints();
  hbot.setPoints(point,np);
  hbot.compute();
  hsoil.setPoints(&point[np],np);
  hsoil.compute();
  hsat.setPoints(&point[2*np],np);
  hsat.compute();
  initial_state->update(*geometry,hsat);
}

void
QtInputView::initPoints(){
  for(size_t i=0;i<np;++i){
    double x=double(i)/(np-1);
    point[i].x=x;
    point[i].y=0.2;
    point[np+i].x=x;
    point[np+i].y=0.8;
    point[2*np+i].x=x;
    point[2*np+i].y=0.5;
  }
}

void
QtInputView::paintGL(){
  if(status==Geom or status==Init){
    glBegin(GL_QUADS);
    double xs=double(pointSize)/width();
    double ys=double(pointSize)/height();
    glColor3f(0,0,0);
    size_t imin=(status==Geom)?0:2*np;
    size_t imax=(status==Geom)?2*np:3*np;
    for(size_t i=imin;i<imax;++i){
      Point& P=point[i];
      double x=P.x;
      double y=P.y;
      glVertex3f(x-xs,y-ys,1);
      glVertex3f(x+xs,y-ys,1);
      glVertex3f(x+xs,y+ys,1);
      glVertex3f(x-xs,y+ys,1);
    }
    glEnd();
  }
  for(auto it=initial_state->tanks.begin();it!=initial_state->tanks.end();++it){
    paintTank(*it);
  }
  for(auto it=source->pumps.begin();it!=source->pumps.end();++it){
    paintPump(*it);
  }
  for(auto it=source->clouds.begin();it!=source->clouds.end();++it){
    paintCloud(*it);
  }
  glColor3f(0.6,0.6,0.6);
  drawSpline(hbot);
  glColor3f(0.6,0.3,0);
  drawSpline(hsoil);
  glColor3f(0,1,1);
  drawSpline(hsat);
  QtView::paintGL();
}

void
QtInputView::paintTank(Tank* tank){
  double l=tank->left;
  double r=tank->right;
  double b=tank->bottom;
  double t=tank->top;
  glLineWidth(2);
  glColor3f(1,0,1);
  glBegin(GL_LINE_LOOP);
  glVertex2f(l,b);
  glVertex2f(r,b);
  glVertex2f(r,t);
  glVertex2f(l,t);
  glEnd();
}

void
QtInputView::paintPump(Pump* pump){
  double a=pump->get_amplitude(time);
  if(a==0) return;
  double l=pump->get_left(time);
  double r=pump->get_right(time);
  double b=pump->get_bottom(time);
  double t=pump->get_top(time);
  double dl=pump->get_left_delta(time);
  double dr=pump->get_right_delta(time);
  double db=pump->get_bottom_delta(time);
  double dt=pump->get_top_delta(time);
  glLineWidth(2);
  if(a>0){
    glColor3f(0,0.6,1);
  }
  else{
    glColor3f(1,0.2,0);
  }
  glLineStipple(3, 0xAAAA);
  glBegin(GL_LINE_LOOP);
  glVertex2f(l,b);
  glVertex2f(r,b);
  glVertex2f(r,t);
  glVertex2f(l,t);
  glEnd();
  glLineWidth(1);
  glEnable(GL_LINE_STIPPLE);
  glBegin(GL_LINE_LOOP);
  glVertex2f(l-dl,b-db);
  glVertex2f(r+dr,b-db);
  glVertex2f(r+dr,t+dt);
  glVertex2f(l-dl,t+dt);
  glEnd();
  glDisable(GL_LINE_STIPPLE);
}

void
QtInputView::paintCloud(Cloud* cloud){
  double a=cloud->get_amplitude(time);
  double amax=cloud->get_amplitude_max();
  if(a==0) return;
  double l=cloud->get_left(time);
  double r=cloud->get_right(time);
  double dl=cloud->get_left_delta(time);
  double dr=cloud->get_right_delta(time);
  double middle=0.97;
  double thick=0.03*a/amax;
  double top=middle+thick;
  double bottom=middle-thick;

  glLineWidth(1);
  glColor3f(0.5,0.5,0.5);
  glLineWidth(1);
  //glEnable(GL_LINE_STIPPLE);
  glBegin(GL_POLYGON);
  glVertex2f(l-dl,middle);
  glVertex2f(l,top);
  glVertex2f(r,top);
  glVertex2f(r+dr,middle);
  glVertex2f(r,bottom);
  glVertex2f(l,bottom);
  glEnd();
  //glDisable(GL_LINE_STIPPLE);
}

void
QtInputView::mousePressEvent(QMouseEvent* event){
  if(status==Geom or status==Init){
    size_t p=findPoint(event->x(),height()-event->y());
    if(status==Geom){
      selected=(p<2*np)?p:3*np;
    }
    else{
      selected=(p>=2*np)?p:3*np;
    }
  }
}

void
QtInputView::mouseMoveEvent(QMouseEvent* event){
  if(selected<3*np){
    double mx=double(event->x())/width();
    double my=1-double(event->y())/height();
    moveSelected(mx,my);
  }
}

size_t
QtInputView::findPoint(int x,int y){
  double w=width();
  double h=height();
  for(size_t i=0;i<3*np;++i){
    int px=point[i].x*w;
    int py=point[i].y*h;
    if(abs(x-px)<pointSize and abs(y-py)<pointSize) return i;
  }
  return 3*np;
}

void
QtInputView::updateGeometry(){
  geometry->update(input_geometry->get_lX(),input_geometry->get_nX(),input_geometry->get_depth(),input_geometry->get_nZ_max(),hsoil,hbot);
  initial_state->update(*geometry,hsat);
  update();
}

void
QtInputView::updateInitialState(){
  update();
}

void
QtInputView::updateSource(){
  update();
}
void
QtInputView::drawSpline(Spline& S){
  double w=width();
  glLineWidth(3);
  glBegin(GL_LINE_STRIP);
  for(int i=0;i<=w;i+=2){
    double x=i/w;
    glVertex2f(x,S(x));
  }
  glEnd();
}

void
QtInputView::moveSelected(double x,double y){
  double xp=point[selected].x;
  double yp=point[selected].y;
  if((selected%np)!=0 and (selected%np)!=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 if(selected<2*np) hsoil.compute();
  else hsat.compute();

  if(selected<2*np){
    double w=width();
    bool ok=true;
    for(int i=0;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();
        update();
        return;
      }
    }
  }
  update();
}

void
QtInputView::mouseReleaseEvent(QMouseEvent* event){
  if(selected<3*np) updateGeometry();
}
