/*********************************************************************/
/*                                                                   */
/* Copyright 2022-2023 Rémi Synave - remi.synave@univ-littoral.fr    */
/*                                                                   */
/* This file is part of DSL.                                         */
/* This software uses Qt to build the Graphical User Interface       */
/* https://www.qt.io/                                                */
/*                                                                   */
/* DSL is free software: you can redistribute it and/or modify       */
/* it under the terms of the GNU General Public License as published */
/* by the Free Software Foundation, either version 3 of the License, */
/* or (at your option) any later version.                            */
/*                                                                   */
/* DSL 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 General Public License */
/* along with DSL. If not, see <http://www.gnu.org/licenses/>.       */
/*                                                                   */
/*********************************************************************/

#include <stdexcept>

#include "StrengthLine.hpp"

StrengthLine::StrengthLine (QPoint * p1, QPoint * p2)
{
  if (p1 == NULL || p2 == NULL)
    throw std::
      invalid_argument ("Points defining a strength line can't be NULL.");
  if (p1->x () == p2->x () && p1->y () == p2->y ())
    throw std::
      invalid_argument ("Points defining a strength line can't be equals.");

  this->p1 = p1;
  this->p2 = p2;
}

std::pair < float, float >
StrengthLine::equation () const
{
  // This method can be called only if a and b are
  // not aligned into a vertical or horizontal line
  float a = ((p1->y () - p2->y ()) * 1.0) / (p1->x () - p2->x ());
  float b = p1->y () - a * p1->x ();
  return std::make_pair (a, b);
}

std::pair < QPoint *, QPoint * >StrengthLine::toDraw (QImage * img) const
{
  // Methode qui va calculer les points pour l'affichage des droites
  // sur l'image passées en paramètre. Calcul rapide donc
  // les points peuvent sortir de l'image.

  // ligne verticale
  if (p1->x () == p2->x ())
    return std::make_pair (new QPoint (p1->x (), 0),
			   new QPoint (p1->x (), img->height ()));

  // ligne horizontale
  if (p1->y () == p2->y ())
    return std::make_pair (new QPoint (0, p1->y ()),
			   new QPoint (img->width (), p1->y ()));

  // Equation de la droite et on prend les points gauche et droite de la ligne
  std::pair < float, float >
    eq = this->equation ();
  float
    a = std::get < 0 > (eq);
  float
    b = std::get < 1 > (eq);

  return std::make_pair (new QPoint (0, b),
			 new QPoint (img->width (), a * img->width () + b));
}

std::pair < QPoint *, QPoint * >StrengthLine::interpolateToEdge (QImage * img) const
{
  // Methode qui va calculer les points sur les bords des images
  // en fonction des deux points attributs qui définissent
  // la ligne.

  // ligne verticale
  if (p1->x () == p2->x ())
    return std::make_pair (new QPoint (p1->x (), 0),
			   new QPoint (p1->x (), img->height ()));

  // ligne horizontale
  if (p1->y () == p2->y ())
    return std::make_pair (new QPoint (0, p1->y ()),
			   new QPoint (img->width (), p1->y ()));

  // Equation de la droite et on prend les points gauche et droite de la ligne
  std::pair < float, float >
    eq = this->equation ();
  float
    a = std::get < 0 > (eq);
  float
    b = std::get < 1 > (eq);

  if(a>0)
    {
      if(b<0)
	{
	  if((a*img->width()+b) > img->height())
	    {
	      // |------------------------------------------|
	      // |           *                              |
	      // |           *                              |
	      // |            *                             |
	      // |            *                             |
	      // |             *                            |
	      // |             *                            |
	      // |              *                           |
	      // |              *                           |
	      // |               *                          |
	      // |------------------------------------------|
	      
	      return std::make_pair (new QPoint (-1*(b/a), 0),
				     new QPoint ((img->height()-b)/a, img->height ()));
	    }
	  else
	    {
	      // |------------------------------------------|
	      // |                           ***            |
	      // |                              ***         |
	      // |                                 ***      |
	      // |                                    ***   |
	      // |                                       ***|
	      // |                                          |
	      // |                                          |
	      // |                                          |
	      // |                                          |
	      // |------------------------------------------|

	      return std::make_pair (new QPoint (-1*(b/a), 0),
				     new QPoint (img->width (), a * img->width () + b));
	    }
	}
      else // a>0 and b>0
	{
	  
	  if((a*img->width()+b) > img->height())
	    {
	      // |------------------------------------------|
	      // |                                          |
	      // |                                          |
	      // |*                                         |
	      // | *                                        |
	      // |  *                                       |
	      // |   *                                      |
	      // |    *                                     |
	      // |     *                                    |
	      // |      *                                   |
	      // |------------------------------------------|
	      
	      return std::make_pair (new QPoint (0, b),
				     new QPoint ((img->height () -b )/a, img->height ()));
	    }
	  else
	    {
	      // |------------------------------------------|
	      // |                                          |
	      // |********                                  |
	      // |        ********                          |
	      // |                ********                  |
	      // |                        ********          |
	      // |                                ********  |
	      // |                                        **|
	      // |                                          |
	      // |                                          |
	      // |------------------------------------------|
	      
	      return std::make_pair (new QPoint (0, b),
				     new QPoint (img->width(), a*img->width ()+b));
	    }
	}
    }
  else // a<0
    {
      if((a*img->width()+b)>0)
	{
	  if(b > img->height())
	    {
	      // |------------------------------------------|
	      // |                                          |
	      // |                                          |
	      // |                                        * |
	      // |                                      *   |
	      // |                                    *     |
	      // |                                  *       |
	      // |                                *         |
	      // |                              *           |
	      // |                            *             |
	      // |------------------------------------------|
	      
	      return std::make_pair (new QPoint ((img->height()-b)/a, img->height()),
				     new QPoint (img->width(), a*img->width()+b));
	    }
	  else
	    {
	      // |------------------------------------------|
	      // |                                          |
	      // |                                          |
	      // |                                        **|
	      // |                                ********  |
	      // |                        ********          |
	      // |                ********                  |
	      // |        ********                          |
	      // |********                                  |
	      // |                                          |
	      // |------------------------------------------|

	      return std::make_pair (new QPoint (0, b),
				     new QPoint (img->width (), a * img->width () + b));
	    }
	}
      else // a>0 and (a*img->width()+b) < 0
	{
	  
	  if(b > img->height())
	    {
	      // |------------------------------------------|
	      // |               *                          |
	      // |               *                          |
	      // |               *                          |
	      // |              *                           |
	      // |              *                           |
	      // |              *                           |
	      // |             *                            |
	      // |             *                            |
	      // |             *                            |
	      // |------------------------------------------|
	      
	      return std::make_pair (new QPoint (-1*(b/a), 0),
				     new QPoint ((img->height()-b)/a, img->height ()));
	    }
	  else
	    {
	      // |------------------------------------------|
	      // |        *                                 |
	      // |      *                                   |
	      // |    *                                     |
	      // |  *                                       |
	      // |*                                         |
	      // |                                          |
	      // |                                          |
	      // |                                          |
	      // |                                          |
	      // |------------------------------------------|
	      
	      return std::make_pair (new QPoint (0, b),
				     new QPoint (-1*(b/a), 0));
	    }
	}
    }
  
  return std::make_pair (new QPoint (*p1),
			 new QPoint (*p2));
}
