/***************************************************************************
                          lines.cpp  -  description
                             -------------------
    begin                : Son Apr 14 2002
    copyright            : (C) 2002 by Birgit Schulz
    email                : B.Schulz@Superlehrer.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/


#include <knuminput.h>
#include <kpushbutton.h>
#include <ktextbrowser.h>
#include <klocale.h>
#include <kapplication.h>

#include <qlabel.h>
#include <qstring.h>
#include <qlayout.h>
//Added by qt3to4:
#include <QPaintEvent>
#include <Q3VBoxLayout>

#include <lines.h>

#include <../kplotwidget.h>

Lines::Lines(QWidget *parent, const char *name ) : LinesD(parent,name)
{


    QWidget *viewPlot = new QWidget ( LinePlotFrame, 0);

    Q3VBoxLayout *vlay1 = new Q3VBoxLayout( viewPlot, 0, -1 );

    pw = new KPlotWidget( -100.0, 100.0, -100.0, 100.0, viewPlot);

    li = new LineInput();

    pw->setShowAxes( false );
    pw->setShowTickMarks( false );
    pw->setBGColor( QColor( "black" ) );
    pw->setFGColor( QColor ( "white") );

    pw->setShowCartAxis( true );
    pw->setShowCartTickMarks( true );
    pw->setShowCartTickLabels( true );
    pw->setShowDegreeCircle( false );

    vlay1->addWidget( pw );

    viewPlot->resize( 400, 400 );

    connect( li->kIntSpinBoxPoint1x, SIGNAL(valueChanged( int )), SLOT( slotUpdateLines()) );
    connect( li->kIntSpinBoxPoint1y, SIGNAL(valueChanged( int )), SLOT( slotUpdateLines()) );
    connect( li->kIntSpinBoxPoint2x, SIGNAL(valueChanged( int )), SLOT( slotUpdateLines()) );
    connect( li->kIntSpinBoxPoint2y, SIGNAL(valueChanged( int )), SLOT( slotUpdateLines()) );
    connect( li->kIntSpinBoxPoint1x, SIGNAL(valueChanged( int )), SLOT( slotCalculate()) );
    connect( li->kIntSpinBoxPoint1y, SIGNAL(valueChanged( int )), SLOT( slotCalculate()) );
    connect( li->kIntSpinBoxPoint2x, SIGNAL(valueChanged( int )), SLOT( slotCalculate()) );
    connect( li->kIntSpinBoxPoint2y, SIGNAL(valueChanged( int )), SLOT( slotCalculate()) );

    connect( li->kIntSpinBoxGradient, SIGNAL(valueChanged( int )), SLOT( slotUpdateLines()) );
    connect( li->kIntSpinBoxGradient, SIGNAL(valueChanged( int )), SLOT( slotCalculate()) );

    connect( li->kIntSpinBoxLine1mx, SIGNAL(valueChanged( int )), SLOT( slotUpdateLines()) );
    connect( li->kIntSpinBoxLine1mx, SIGNAL(valueChanged( int )), SLOT( slotCalculate()) );
    connect( li->kIntSpinBoxLine2mx, SIGNAL(valueChanged( int )), SLOT( slotUpdateLines()) );
    connect( li->kIntSpinBoxLine2mx, SIGNAL(valueChanged( int )), SLOT( slotCalculate()) );

    connect( li->kIntSpinBoxLine1c, SIGNAL(valueChanged( int )), SLOT( slotUpdateLines()) );
    connect( li->kIntSpinBoxLine1c, SIGNAL(valueChanged( int )), SLOT( slotCalculate()) );
    connect( li->kIntSpinBoxLine2c, SIGNAL(valueChanged( int )), SLOT( slotUpdateLines()) );
    connect( li->kIntSpinBoxLine2c, SIGNAL(valueChanged( int )), SLOT( slotCalculate()) );


    TextLabelInformation->setText(i18n("Select a Straightline Function below"));

    li->TextLabelFirstInfoPoint->hide();                    //1st point frame
    li->kIntSpinBoxPoint1x->hide();
    li->textLabel3->hide();
    li->line5->hide();
    li->textLabel2->hide();
    li->kIntSpinBoxPoint1y->hide();
    li->textLabel4->hide();

    li->TextLabelSecondInfoPoint->hide();                   //2nd point frame
    li->kIntSpinBoxPoint2x->hide();
    li->textLabel3_2->hide();
    li->line1->hide();
    li->textLabel2_2->hide();
    li->kIntSpinBoxPoint2y->hide();
    li->textLabel4_2->hide();

    li->textLabelFirtsInfoLine->hide();                     //1st line frame
    li->kIntSpinBoxLine1mx->hide();
    li->textLabel6->hide();
    li->kIntSpinBoxLine1c->hide();
    li->textLabel5->hide();

    li->textLabelSecondInfoLine->hide();                    //2nd line frame
    li->kIntSpinBoxLine2mx->hide();
    li->textLabel6_2->hide();
    li->kIntSpinBoxLine2c->hide();
    li->textLabel5_2->hide();

    li->textLabel1->hide();                                 //gradient frame
    li->kIntSpinBoxGradient->hide();

    initObjects();

    slotClear();
}

Lines::~Lines()
{}

void Lines::paintEvent( QPaintEvent* )
{
    pw->update();
}

void Lines::initObjects()
{
    KPlotObject *line_one;
    KPlotObject *line_two;

    line_one = new KPlotObject( "1", "red", KPlotObject::POLYGON, 2, KPlotObject::SOLID );
    line_one->addPoint( new DPoint( 0.0, 0.0 ) );
    line_one->addPoint( new DPoint( 100.0, 100.0 ) );
    pw->addObject( line_one );

    line_two = new KPlotObject( "2", "green", KPlotObject::POLYGON, 2, KPlotObject::SOLID );
    line_two->addPoint( new DPoint( 0.0, 0.0 ) );
    line_two->addPoint( new DPoint( -100.0, -100.0 ) );
    pw->addObject( line_two );
}

void Lines::slotUpdateLines()
{
    KPlotObject *_1 = pw->object( 0 );
    KPlotObject *_2 = pw->object( 1 );

	_1->setHidden( true );							//Red Line
	_2->setHidden( true );							//Green Line

    switch (m_eSelected)
    {
    case TwoPoints:
        {
            _1->setHidden( false );
            int x1, y1, x2, y2;
            x1 = li->kIntSpinBoxPoint1x->value();
            y1 = li->kIntSpinBoxPoint1y->value();
            x2 = li->kIntSpinBoxPoint2x->value();
            y2 = li->kIntSpinBoxPoint2y->value();

            bool bSucess;
            double m = Gradient(x1, x2, y1, y2, bSucess);
            double c = AxisCut(m, x1, y1);

            double p_x1 = 100.0;
            double p_x2 = -100.0;

            double p_y1 = m*p_x1+c;                 //Calc the Y-Values if x = 100;
            double p_y2 = m*p_x2+c;                 //Calc the Y-Values if x = -100;

            if ( x1 != x2 )                         //Plot normal function
            {
                _1->point( 0 )->setX( 100.0 );
                _1->point( 0 )->setY( p_y1 );
                _1->point( 1 )->setX( -100.0 );
                _1->point( 1 )->setY( p_y2 );
            }

            else if   ( x1 == x2 )                  //Plot if gradient undefined
            {
                _1->point( 0 )->setX( x1 );
                _1->point( 0 )->setY( 100.0 );
                _1->point( 1 )->setX( x2 );
                _1->point( 1 )->setY( -100.0 );
            }
            break;
        }


    case OnePoint: //1 Point and Gradient
        {
            _1->setHidden( false );
            _2->setHidden( true );
            int x1, y1, m;

            x1 = li->kIntSpinBoxPoint1x->value();
            y1 = li->kIntSpinBoxPoint1y->value();
            m = li->kIntSpinBoxGradient->value();

            double c = AxisCut(m, x1, y1);

            double p_x1 = 100.0;
            double p_x2 = -100.0;

            double p_y1 = m*p_x1+c;
            double p_y2 = m*p_x2+c;

            _1->point( 0 )->setX( p_x1 );
            _1->point( 0 )->setY( p_y1 );
            _1->point( 1 )->setX( p_x2 );
            _1->point( 1 )->setY( p_y2 );

            break;
        }


    case AxisSection: //X and Y Axis Cuts
        {
            _1->setHidden( false );
            _2->setHidden( true );
            int m, c;

            m = li->kIntSpinBoxLine1mx->value();
            c = li->kIntSpinBoxLine1c->value();

            double p_x1 = 100.0;
            double p_x2 = -100.0;

            double p_y1 = m*p_x1+c;
            double p_y2 = m*p_x2+c;

            _1->point( 0 )->setX( p_x1 );
            _1->point( 0 )->setY( p_y1 );
            _1->point( 1 )->setX( p_x2 );
            _1->point( 1 )->setY( p_y2 );

            break;
        }

    case Section: //Intersect Point with two Lines
        {
            _2->setHidden( false );
            _1->setHidden( false );
            int m1, c1, m2, c2;

            m1 = li->kIntSpinBoxLine1mx->value();
            c1 = li->kIntSpinBoxLine1c->value();
            m2 = li->kIntSpinBoxLine2mx->value();
            c2 = li->kIntSpinBoxLine2c->value();

            double p_x1 = 100.0;
            double p_x2 = -100.0;

            double p_y1_1 = m1*p_x1+c1;
            double p_y2_1 = m1*p_x2+c1;

            double p_y1_2 = m2*p_x1+c2;
            double p_y2_2 = m2*p_x2+c2;

            _1->point( 0 )->setX( p_x1 );
            _1->point( 0 )->setY( p_y1_1 );
            _1->point( 1 )->setX( p_x2 );
            _1->point( 1 )->setY( p_y2_1 );

            _2->point( 0 )->setX( p_x1 );       //fixme
            _2->point( 0 )->setY( p_y1_2 );
            _2->point( 1 )->setX( p_x2 );
            _2->point( 1 )->setY( p_y2_2 );

            break;
        }
    }
    update();
}

void Lines::slotCalculate()
{
    switch (m_eSelected)
    {
    case TwoPoints: //2 Points
        {
            int x1, y1, x2, y2;
            QString qsResult, qsX1, qsY1, qsX2, qsY2, qsC, qsM, qsEquation;
            x1 = li->kIntSpinBoxPoint1x->value();
            y1 = li->kIntSpinBoxPoint1y->value();
            x2 = li->kIntSpinBoxPoint2x->value();
            y2 = li->kIntSpinBoxPoint2y->value();

            qsX1 = li->kIntSpinBoxPoint1x->text();
            qsY1 = li->kIntSpinBoxPoint1y->text();
            qsX2 = li->kIntSpinBoxPoint2x->text();
            qsY2 = li->kIntSpinBoxPoint2y->text();
            bool bSucess;
            double m = Gradient(x1, x2, y1, y2, bSucess);
            if (bSucess == false)
            {
                qsResult = i18n("The line, going through the given points, is vertical.\n"
                                "So it is not a function and every point on this line has the property\n"
                                "x = %1").arg(qsX1);
                KTextBrowserResult->setText(qsResult);
            }
            else
            {
                double c = AxisCut(m, x1, y1);
                qsM = qsM.number(m);
                qsC = qsC.number(c);
                qsResult = i18n("The equation of the line going through the given points is:\n");
                if ( c == 0)
                {
                    qsEquation = "y = " + qsM + "x";
                    qsEquation = qsEquation.simplified();
                }
                else if (c > 0)
                {
                    qsEquation = "y = " + qsM + "x+" + qsC;
                    qsEquation = qsEquation.simplified();
                }
                else
                {
                    qsEquation = "y = " + qsM + "x" + qsC;
                    qsEquation = qsEquation.simplified();
                }

                KTextBrowserResult->setText(qsResult + qsEquation);

                slotUpdateLines();
            }
            break;
        }

    case OnePoint: //1 Point and Gradient
        {
            int x1, y1, m;
            QString qsResult, qsX1, qsY1, qsC, qsM, qsEquation;
            x1 = li->kIntSpinBoxPoint1x->value();
            y1 = li->kIntSpinBoxPoint1y->value();
            m = li->kIntSpinBoxGradient->value();
            double c = AxisCut(m, x1, y1);
            qsX1 = li->kIntSpinBoxPoint1x->text();
            qsY1 = li->kIntSpinBoxPoint1y->text();
            qsC = qsC.number(c);
            qsM = li->kIntSpinBoxGradient->text();

            qsResult = i18n("The line, with the given gradient which is going through the given point, has got the equation:\n\n");
            if ( c == 0)

            {
                qsEquation += "y = " + qsM + "  x ";
                qsEquation = qsEquation.simplified();
            }
            else if (c > 0)
            {
                qsEquation += "y = " + qsM + "  x + " + qsC;
                qsEquation = qsEquation.simplified();
            }
            else
            {
                qsEquation += "y = " + qsM + "  x " + qsC;
                qsEquation = qsEquation.simplified();
            }
            KTextBrowserResult->setText(qsResult + qsEquation);
            break;
        }


    case AxisSection: //X and Y Axis Cuts
        {
            int m, c, ys;
            double xs;
            QString qsResult, qsEquation, qsXs, qsYs;
            m = li->kIntSpinBoxLine1mx->value();
            c = li->kIntSpinBoxLine1c->value();

            if (m == 0)
            {
                qsYs = qsYs.number(ys);
                qsResult = i18n("The line with the given equation is parallel to the x-axis, so it does not intersect it.\n"
                                "The y-axis is intersected at \n"
                                "S( 0 | %1 ).").arg(qsYs);
            }
            else
            {
                ys = c;
                xs = (-1.0)*c/m;
                qsXs = qsXs.number(xs);
                qsYs = qsYs.number(ys);
                qsResult = i18n("The given line crosses the <b>x-axis</b> at<br>"
                                " S<sub>x</sub>( %1 | 0 ) and the <b>y-axis</b> at<br>"
                                " S<sub>y</sub>( 0 | %2 ).").arg(qsXs,qsYs);
            }

            KTextBrowserResult->setText(qsResult);
            break;
        }

    case Section: //Intersect Point with two Lines
        {
            int m1, c1, m2, c2, xs, ys;
            QString qsResult, qsEquation, qsXs, qsYs;
            m1 = li->kIntSpinBoxLine1mx->value();
            c1 = li->kIntSpinBoxLine1c->value();
            m2 = li->kIntSpinBoxLine2mx->value();
            c2 = li->kIntSpinBoxLine2c->value();
            if ((m1 - m2) == 0)
            {
                if ((c1 - c2) == 0)
                {
                    qsResult = i18n("The two given lines are identical, so there are an infinite number of intersecting points.");
                }
                else
                {
                    qsResult = i18n("The two given lines are parallel, so there are no intersecting points.");
                }
            }
            else
            {
                xs = (c2 - c1)/(m1 - m2);
                ys = m1*xs + c1;
                qsXs = qsXs.number(xs);
                qsYs = qsYs.number(ys);
                qsResult = i18n("The intersection point of the two given lines is\n\nS( %1 | %2 ).").arg(qsXs,qsYs);
                qsResult = qsResult.simplified();
            }
            KTextBrowserResult->setText(qsResult);
            break;
        }
    }
}

void Lines::hideInput()
{
    li->TextLabelFirstInfoPoint->hide();                    //1st point frame
    li->kIntSpinBoxPoint1x->hide();
    li->textLabel3->hide();
    li->line5->hide();
    li->textLabel2->hide();
    li->kIntSpinBoxPoint1y->hide();
    li->textLabel4->hide();

    li->TextLabelSecondInfoPoint->hide();                   //2nd point frame
    li->kIntSpinBoxPoint2x->hide();
    li->textLabel3_2->hide();
    li->line1->hide();
    li->textLabel2_2->hide();
    li->kIntSpinBoxPoint2y->hide();
    li->textLabel4_2->hide();

    li->textLabelFirtsInfoLine->hide();                     //1st line frame
    li->kIntSpinBoxLine1mx->hide();
    li->textLabel6->hide();
    li->kIntSpinBoxLine1c->hide();
    li->textLabel5->hide();

    li->textLabelSecondInfoLine->hide();                    //2nd line frame
    li->kIntSpinBoxLine2mx->hide();
    li->textLabel6_2->hide();
    li->kIntSpinBoxLine2c->hide();
    li->textLabel5_2->hide();

    li->textLabel1->hide();                                 //gradient frame
    li->kIntSpinBoxGradient->hide();
}

void Lines::slotClear()
{
    li->kIntSpinBoxPoint1x->setValue( 0 );
    li->kIntSpinBoxPoint1y->setValue( 0 );
    li->kIntSpinBoxPoint2x->setValue( 0 );
    li->kIntSpinBoxPoint2y->setValue( 0 );
    li->kIntSpinBoxGradient->setValue( 0 );
    li->kIntSpinBoxLine1mx->setValue( 0 );
    li->kIntSpinBoxLine1c->setValue( 0 );
    li->kIntSpinBoxLine2mx->setValue( 0 );
    li->kIntSpinBoxLine2c->setValue( 0 );

    KTextBrowserResult->setText(i18n(" "));
}

void Lines::slotShowLinesAxisSection()
{
    slotClear();

    hideInput();

    TextLabelInformation->setText(i18n("Find intersection with axis"));

    KTextBrowserResult->setText(" ");

    li->textLabelFirtsInfoLine->show();                     //1st line frame
    li->kIntSpinBoxLine1mx->show();
    li->textLabel6->show();
    li->kIntSpinBoxLine1c->show();
    li->textLabel5->show();

    m_eSelected = AxisSection;

    li->show();
}

void Lines::slotShowLinesOnePoint()
{
    slotClear();

    hideInput();

    KTextBrowserResult->setText(" ");

    TextLabelInformation->setText(i18n("Find equation/point and gradient"));

    li->TextLabelFirstInfoPoint->show();                    //Point frame
    li->kIntSpinBoxPoint1x->show();
    li->textLabel3->show();
    li->line5->show();
    li->textLabel2->show();
    li->kIntSpinBoxPoint1y->show();
    li->textLabel4->show();

    li->textLabel1->show();                                 //gradient frame
    li->kIntSpinBoxGradient->show();

    m_eSelected = OnePoint;

    li->show();
}

void Lines::slotShowLinesTwoPoints()
{
    KPlotObject *_2 = pw->object( 1 );

    _2->setHidden( true );

    slotClear();

    hideInput();

    TextLabelInformation->setText(i18n("Find equation with two given points"));

    KTextBrowserResult->setText(" ");

    li->TextLabelFirstInfoPoint->show();                    //1st point frame
    li->kIntSpinBoxPoint1x->show();
    li->textLabel3->show();
    li->line5->show();
    li->textLabel2->show();
    li->kIntSpinBoxPoint1y->show();
    li->textLabel4->show();

    li->TextLabelSecondInfoPoint->show();                   //2nd point frame
    li->kIntSpinBoxPoint2x->show();
    li->textLabel3_2->show();
    li->line1->show();
    li->textLabel2_2->show();
    li->kIntSpinBoxPoint2y->show();
    li->textLabel4_2->show();

    m_eSelected = TwoPoints;

    li->show();
}

void Lines::slotShowLinesSection()
{   //Empty result box
    slotClear();

    hideInput();

    KTextBrowserResult->setText(" ");

    TextLabelInformation->setText(i18n("Find intersect-point of two lines"));

    li->textLabelFirtsInfoLine->show();                     //1st line frame
    li->kIntSpinBoxLine1mx->show();
    li->textLabel6->show();
    li->kIntSpinBoxLine1c->show();
    li->textLabel5->show();

    li->textLabelSecondInfoLine->show();                    //2nd line frame
    li->kIntSpinBoxLine2mx->show();
    li->textLabel6_2->show();
    li->kIntSpinBoxLine2c->show();
    li->textLabel5_2->show();

    m_eSelected = Section;

    li->show();
}

double Lines::Gradient(double x1, double x2, double y1, double y2, bool &bSucess)
{
    if ((x1 - x2) == 0)
    {
        bSucess = false;
        return 0;
    }
    else
    {
        bSucess = true;
        double m = (y1 - y2)/(x1 - x2);
        return m;
    }
}

double Lines::AxisCut(double m, double x1, double y1)
{
    double c = y1 - m*x1;
    return c;
}

#include "lines.moc"
