/***********************************************************************
**
**   flighttask.cpp
**
**   This file is part of KFLogEmbedded.
**
************************************************************************
**
**   Copyright (c):  2002 by Heiner Lamprecht
**
**   This file is distributed under the terms of the General Public
**   Licence. See the file COPYING for more information.
**
**   $Id: flighttask.cpp,v 1.14 2005/02/26 20:06:36 axel Exp $
**
***********************************************************************/

#include <cmath>
#include <qmessagebox.h>
#include <qobject.h>

#include "flighttask.h"
#include "mapcalc.h"
#include "distance.h"

#define PRE_ID ( loop - 1 )
#define CUR_ID loop
#define NEXT_ID ( loop + 1 )

/* Die Einstellungen können mal in die Voreinstellungsdatei wandern ... */
#define FAI_POINT 2.0
#define NORMAL_POINT 1.75
#define R1 ((int) rint(3000.0 / glMapMatrix->getScale()))
#define R2 ((int) rint((500.0 / glMapMatrix->getScale())))

FlightTask::FlightTask(QString fName)
  : BaseFlightElement("task", BaseMapElement::Task, fName),
    isOrig(false),
    __planningType(RouteBased),
    flightType(FlightTask::NotSet),
    _fName(fName)
{
  wpList.setAutoDelete(true);
  __updateTask();
}

FlightTask::FlightTask(QList<wayPoint>& wpL, bool isO, QString fName)
  : BaseFlightElement("task", BaseMapElement::Task, fName),
    isOrig(isO),
    __planningType(RouteBased),
    flightType(FlightTask::NotSet),
    _fName(fName)
{
  wpList.setAutoDelete(true);

  // @AP: Make a deep copy from all elements of the passed list

  for( uint i=0; i < wpL.count(); i++ )
    {
      wpList.append( new wayPoint(*wpL.at(i)) );
    }

  // warning("FlightTask(QList<wayPoint> wpL, bool isO, QString fName)");
  // only do this if wpList is not empty!
  if (wpList.count()  != 0)
    {
      for(unsigned int loop = 0; loop < wpList.count(); loop++)
        {
          wpList.at(loop)->type = FlightTask::FreeP;
          wpList.at(loop)->sector1 = 0;
          wpList.at(loop)->sector2 = 0;
          wpList.at(loop)->sectorFAI = 0;
        }

      __updateTask();
   }
}

FlightTask::~FlightTask()
{
}

void FlightTask::__checkType()
{
  /**
   * Prooves the type of the task.
   **/
  if (wpList.count() ==0) return;
  
  distance_task = 0;
  distance_total = 0;
  double distance_task_d = 0;

  for(unsigned int loop = 1; loop <= wpList.count() - 1; loop++)
  {
//warning("distance: %f",wpList.at(loop)->distance);
      distance_total += wpList.at(loop)->distance;
  }
//warning("Total Distance: %f",distance_total);

  if(wpList.count() < 4)
    {
      flightType = FlightTask::NotSet;
      return;
    }


  distance_task = distance_total - wpList.at(1)->distance
                                 - wpList.at(wpList.count() - 1)->distance;

  if(dist(wpList.at(1),wpList.at(wpList.count() - 2)) < 1.0)
    {
      switch(wpList.count() - 4)
        {
          case 0:
            // Fehler
            flightType = FlightTask::NotSet;
            break;
          case 1:
            // Zielrückkehr
            flightType = FlightTask::ZielR;
            break;
          case 2:
            // FAI Dreieck
            if(isFAI(distance_task,wpList.at(2)->distance,
                wpList.at(3)->distance, wpList.at(4)->distance))
               flightType = FlightTask::FAI;
            else
              // Dreieck
              flightType = FlightTask::Dreieck;
            break;
          case 3:
            // Start auf Schenkel oder Vieleck
            // Vieleck Ja/Nein kann endgültig erst bei der Analyse des Fluges
            // bestimmt werden!
            //
            // Erste Abfrage je nachdem ob Vieleck oder Dreieck mehr Punkte geben
            // würde
            distance_task_d = distance_task - wpList.at(2)->distance
                 - wpList.at(5)->distance + dist(wpList.at(2), wpList.at(4));

            if(isFAI(distance_task_d, dist(wpList.at(2), wpList.at(4)),
                  wpList.at(3)->distance, wpList.at(4)->distance))
              {
                if(distance_task > distance_task_d * (1.0 + 1.0/3.0))
                    flightType = FlightTask::Vieleck;
                else
                  {
                    flightType = FlightTask::FAI_S;
                    distance_task = distance_task_d;
                  }
              }
            else
              {
                if(distance_task > distance_task_d * (1.0 + 1.0/6.0))
                    flightType = FlightTask::Vieleck;
                else
                  {
                    flightType = FlightTask::Dreieck_S;
                    distance_task = distance_task_d;
                  }
              }
            break;
          case 5:
            // 2x Dreieck nur als FAI gültig
            flightType = Unknown;
            if( (distance_task / 2 <= 100) && (wpList.at(1) == wpList.at(4)) &&
                    (wpList.at(2) == wpList.at(5)) &&
                    (wpList.at(3) == wpList.at(6)) &&
                    isFAI(distance_task / 2, wpList.at(2)->distance,
                            wpList.at(3)->distance, wpList.at(4)->distance))
                flightType = FlightTask::FAI_2;
            break;
          case 6:
            // 2x Dreieck auf Schenkel FAI
            flightType = FlightTask::Unknown;
            distance_task = distance_task - wpList.at(2)->distance
                 - wpList.at(5)->distance
                 + dist(wpList.at(2), wpList.at(4)) * 2;

            if( (distance_task / 2 <= 100) &&
                    (wpList.at(2) == wpList.at(5)) &&
                    (wpList.at(3) == wpList.at(6)) &&
                    (wpList.at(4) == wpList.at(7)) &&
                    isFAI(distance_task, dist(wpList.at(2), wpList.at(4)),
                      wpList.at(3)->distance, wpList.at(4)->distance))
              flightType = FlightTask::FAI_S2;
            break;
          case 8:
            // 3x FAI Dreieck
            flightType = Unknown;
            if( (distance_task / 3 <= 100) &&
                    (wpList.at(1) == wpList.at(4)) &&
                    (wpList.at(2) == wpList.at(5)) &&
                    (wpList.at(3) == wpList.at(6)) &&
                    (wpList.at(1) == wpList.at(7)) &&
                    (wpList.at(2) == wpList.at(8)) &&
                    (wpList.at(3) == wpList.at(9)) &&
                    isFAI(distance_task / 3, wpList.at(2)->distance,
                        wpList.at(3)->distance, wpList.at(4)->distance))
                flightType = FlightTask::FAI_3;
            break;
          case 9:
            // 3x FAI Dreieck Start auf Schenkel
            distance_task = distance_task - wpList.at(2)->distance
                 - wpList.at(5)->distance
                 + dist(wpList.at(2), wpList.at(4)) * 3;

            flightType = Unknown;
            if( (distance_task / 3 <= 100) &&
                    (wpList.at(2) == wpList.at(5)) &&
                    (wpList.at(3) == wpList.at(6)) &&
                    (wpList.at(4) == wpList.at(7)) &&
                    (wpList.at(2) == wpList.at(8)) &&
                    (wpList.at(3) == wpList.at(9)) &&
                    (wpList.at(4) == wpList.at(10)) &&
                     isFAI(distance_task, dist(wpList.at(2), wpList.at(4)),
                        wpList.at(3)->distance, wpList.at(4)->distance))
              flightType = FlightTask::FAI_S3;
          default:
            flightType = FlightTask::Unknown;
        }
    }
  else
    {
      if(wpList.count() <= 1 + 4)
          // Zielstrecke
          flightType = FlightTask::ZielS;
      else
          flightType = FlightTask::Unknown;
    }
}

double FlightTask::__sectorangle(unsigned int loop, bool /*isDraw not used */)
{
  double /* nextAngle = 0.0, preAngle = 0.0, not used */ sectorAngle = 0.0;
  
  // In some cases during planning, this method is called with wrong
  // loop-values. Therefore we must check the id before calculating
  // the direction
  switch(wpList.at(loop)->type)
    {
      case Begin:
        // directions to the next point
        if(wpList.count() >= loop + 1)
            /*sectorAngle = polar(
                ( wpList.at(CUR_ID)->projP.x() - wpList.at(NEXT_ID)->projP.x() ),
                ( wpList.at(CUR_ID)->projP.y() - wpList.at(NEXT_ID)->projP.y() ) );*/
              sectorAngle = getBearing(wpList.at(CUR_ID)->projP, wpList.at(NEXT_ID)->projP);  
        else
            sectorAngle = 0;
        break;
      case RouteP:
        if(loop >= 1 && wpList.count() >= loop + 1)
          {
/*            // directions to the previous point
            //preAngle = polar(
            //    ( wpList.at(CUR_ID)->projP.x() - wpList.at(PRE_ID)->projP.x() ),
            //    ( wpList.at(CUR_ID)->projP.y() - wpList.at(PRE_ID)->projP.y() ) );
            preAngle = polar(
                ( wpList.at(PRE_ID)->projP.x() - wpList.at(CUR_ID)->projP.x() ),
                ( wpList.at(PRE_ID)->projP.y() - wpList.at(CUR_ID)->projP.y() ) );
            // direction to the following point:
            //nextAngle = polar(
            //    ( wpList.at(CUR_ID)->projP.x() - wpList.at(NEXT_ID)->projP.x() ),
            //   ( wpList.at(CUR_ID)->projP.y() - wpList.at(NEXT_ID)->projP.y() ) );
            nextAngle = polar(
                ( wpList.at(NEXT_ID)->projP.x() - wpList.at(CUR_ID)->projP.x() ),
                ( wpList.at(NEXT_ID)->projP.y() - wpList.at(CUR_ID)->projP.y() ) );

            sectorAngle = (preAngle + nextAngle) / 2.0;
            if( ( preAngle < PI / 2.0 && nextAngle > 1.5 * M_PI ) ||
                ( nextAngle < PI / 2.0 && preAngle > 1.5 * M_PI ) )
                sectorAngle = sectorAngle - M_PI;
*/
            sectorAngle=outsideVector(wpList.at(CUR_ID)->projP, wpList.at(PRE_ID)->projP, wpList.at(NEXT_ID)->projP);
          }
        else
            sectorAngle = 0;
        break;
      case End:
        if(loop >= 1 && loop < wpList.count())
          {
            // direction to the previous point:
            /*sectorAngle = polar(
                ( wpList.at(CUR_ID)->projP.x() - wpList.at(PRE_ID)->projP.x() ),
                ( wpList.at(CUR_ID)->projP.y() - wpList.at(PRE_ID)->projP.y() ) );*/
            sectorAngle=getBearing( wpList.at( CUR_ID )->projP, wpList.at ( PRE_ID )->projP );
          }
        else
            sectorAngle = 0;
        break;
    }

  // Nur nötig bei der Überprüfung der Wegpunkte,
  // würde beim Zeichnen zu Fehlern führen
  //if(!isDraw) sectorAngle += M_PI;

  if(sectorAngle > (2 * M_PI)) sectorAngle = sectorAngle - (2 * M_PI);

  wpList.at(CUR_ID)->angle = sectorAngle;
  //qDebug("sectorangle: %f", sectorAngle);

  return sectorAngle;
}

void FlightTask::__setWaypointType()
{
  /*
   * Setzt den Status der Wendepunkte und die Distanzen
   */
  unsigned int cnt = wpList.count();
  if (cnt == 0) return;
  
  if (cnt > 0) {
    wpList.at(0)->type = FlightTask::FreeP;
  }

  // First waypoint has always distance 0.0
  wpList.at(0)->distance = 0.0;

  // Distances
  for(unsigned int n = 1; n  < cnt; n++)
    {
      wpList.at(n)->distance = dist(wpList.at(n-1),wpList.at(n));
      wpList.at(n)->type = FlightTask::FreeP;
    }

  // Kein Wendepunkt definiert
  if (cnt < 4)  return;

  wpList.at(0)->type = FlightTask::TakeOff;
  wpList.at(1)->type = FlightTask::Begin;
  wpList.at(cnt - 2)->type = FlightTask::End;
  wpList.at(cnt - 1)->type = FlightTask::Landing;

  for(unsigned int n = 2; n + 2 < cnt; n++) {
    wpList.at(n)->type = FlightTask::RouteP;
  }
}

int FlightTask::getTaskType() const  {  return flightType;  }

QString FlightTask::getTaskTypeString() const
{
  switch(flightType)
    {
      case FlightTask::NotSet:       return QObject::tr("not set");
      case FlightTask::ZielS:        return QObject::tr("Free Distance");
      case FlightTask::ZielR:        return QObject::tr("Free Out and Return Distance");
      case FlightTask::FAI:          return QObject::tr("FAI Triangle");
      case FlightTask::Dreieck:      return QObject::tr("Triangle");
      case FlightTask::FAI_S:        return QObject::tr("FAI Triangle Start on leg");
      case FlightTask::Dreieck_S:    return QObject::tr("Triangle Start on leg");
      case FlightTask::Abgebrochen:  return QObject::tr("Broken off");
    }

  return QObject::tr("Unknown");
}

bool FlightTask::isFAI(double d_wp, double d1, double d2, double d3)
{
  if( ( d_wp < 500.0 ) &&
      ( d1 >= 0.28 * d_wp && d2 >= 0.28 * d_wp && d3 >= 0.28 * d_wp ) )
      // small FAI
      return true;
  else if( ( d1 > 0.25 * d_wp && d2 > 0.25 * d_wp && d3 > 0.25 * d_wp ) &&
           ( d1 <= 0.45 * d_wp && d2 <= 0.45 * d_wp && d3 <= 0.45 * d_wp ) )
      // large FAI
      return true;

  return false;
}

void FlightTask::drawMapElement(CuPainter* targetPainter,
    CuPainter* maskPainter)
{
  qDebug ("FlightTask::drawMapElement");
  // Strecke und Sektoren zeichnen
//  if(flightType != NotSet)
  if(flightType != 99999)
    {
      QRect viewport(-10-R1, -10-R1, 250+R1, 250+R1);

      for(unsigned int loop = 0; loop < wpList.count(); loop++)
        {
          /*
           * w1 ist die Winkelhalbierende des Sektors!!!
           *      (Angaben in 1/16 Grad)
           */
          int w1 = (int) rint(( ( glMapMatrix->map(wpList.at(loop)->angle) + M_PI ) / M_PI )
			      * 180.0 * 16.0 * -1.0);
          
          QPoint tempP (glMapMatrix->map(wpList.at(loop)->projP));
          int qx = (int) rint(-R1 + tempP.x());
          int qy = (int) rint(-R1 + tempP.y());
          int gx = (int) rint(-R2 + tempP.x());
          int gy = (int) rint(-R2 + tempP.y());

          if(loop)
            {
              bBoxTask.setLeft(MIN(tempP.x(), bBoxTask.left()));
              bBoxTask.setTop(MAX(tempP.y(), bBoxTask.top()));
              bBoxTask.setRight(MAX(tempP.x(), bBoxTask.right()));
              bBoxTask.setBottom(MIN(tempP.y(), bBoxTask.bottom()));
            }
          else
            {
              bBoxTask.setLeft(tempP.x());
              bBoxTask.setTop(tempP.y());
              bBoxTask.setRight(tempP.x());
              bBoxTask.setBottom(tempP.y());
            }

          switch(wpList.at(loop)->type)
            {
              case FlightTask::RouteP:
                if (viewport.contains(tempP)) {
                  targetPainter->setPen(QPen(QColor(50, 50, 50), 2));
                  targetPainter->setBrush(QColor(255, 110, 110));
                  targetPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 1440, 2880);
                  targetPainter->setBrush(QColor(110, 255, 110));
                  targetPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  targetPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);

                  // Inneren Sektor erneut zeichnen, damit Trennlinien
                  // zwischen Sekt. 1 und Zylinder verschwinden
                  targetPainter->setPen(QPen::NoPen);
                  targetPainter->drawEllipse(gx + 2, gy + 2,
                      (2 * R2) - 4, (2 * R2) - 4);

                  maskPainter->setPen(QPen(Qt::color1, 2));
                  maskPainter->setBrush(QBrush(Qt::color1));
                  maskPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 1440, 2880);
                  maskPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  maskPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);
                }
                
                if(loop)
                  {
                    if((flightType == FAI_S || flightType == Dreieck_S) &&
                            loop == 2)
                        targetPainter->setPen(QPen(QColor(50, 50, 50), 3));
                    else
                        targetPainter->setPen(QPen(QColor(150, 0, 200), 3));

                    maskPainter->setBrush(QBrush::SolidPattern);
                    targetPainter->setBrush(QBrush::SolidPattern);
                    maskPainter->setPen(QPen(Qt::color1, 3));
                    targetPainter->drawLine(
                        glMapMatrix->map(wpList.at(loop - 1)->projP),
                        glMapMatrix->map(wpList.at(loop)->projP), true);
                    maskPainter->drawLine(
                        glMapMatrix->map(wpList.at(loop - 1)->projP),
                        glMapMatrix->map(wpList.at(loop)->projP), true);
                  }
                break;

              case FlightTask::Begin:
                if (viewport.contains(tempP)) {
                  targetPainter->setPen(QPen(QColor(50, 50, 50), 2));
                  targetPainter->setBrush(QBrush(Qt::red,
                      QBrush::BDiagPattern));
                  targetPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  targetPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);
                  //we need to draw again, because the border will not be drawn above (bug in Qt/E)
                  targetPainter->setPen(QPen(Qt::red, 2));
                  targetPainter->setBrush(Qt::NoBrush);
                  targetPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  targetPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);

                  maskPainter->setPen(QPen(Qt::color1, 2));
                  maskPainter->setBrush(QBrush(Qt::color1, QBrush::BDiagPattern));
                  maskPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  maskPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);
                  //we need to draw again, because the border will not be drawn above (bug in Qt/E)
                  maskPainter->setPen(QPen(Qt::color1, 2));
                  maskPainter->setBrush(Qt::NoBrush);
                  maskPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  maskPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);
                }
                // Linie von Startpunkt zum Aufgaben Beginn
                //
                if(loop)
                  {
                    maskPainter->setBrush(QBrush::SolidPattern);
                    targetPainter->setBrush(QBrush::SolidPattern);
                    targetPainter->setPen(QPen(Qt::red, 4));
                    maskPainter->setPen(QPen(Qt::color1, 2));
                    targetPainter->drawLine(
                        glMapMatrix->map(wpList.at(loop - 1)->projP),
                        glMapMatrix->map(wpList.at(loop)->projP), true);
                    maskPainter->drawLine(
                        glMapMatrix->map(wpList.at(loop - 1)->projP),
                        glMapMatrix->map(wpList.at(loop)->projP), true);
//                   warning("zeichne Linie zum AufgabenBeginn loop: %d",loop);
//                   cout << "von " << wpList.at(loop - 1)->name << " nach: " << wpList.at(loop)->name << endl;
                  }
                break;

              case FlightTask::End:
                if (viewport.contains(tempP)) {
                  targetPainter->setPen(QPen(QColor(50, 50, 50), 2));
                  targetPainter->setBrush(QBrush(Qt::blue,
                      QBrush::FDiagPattern));

                  targetPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  targetPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);

                  //we need to draw again, because the border will not be drawn above (bug in Qt/E)
                  targetPainter->setPen(QPen(Qt::blue, 2));
                  targetPainter->setBrush(QBrush(Qt::blue, QBrush::NoBrush));

                  targetPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  targetPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);
                  
                  targetPainter->setPen(QPen(QColor(50, 50, 50), 3));
                  targetPainter->drawLine(
                      glMapMatrix->map(wpList.at(loop-1)->projP),
                      glMapMatrix->map(wpList.at(loop)->projP));

                  maskPainter->setPen(QPen(Qt::color1, 2));
                  maskPainter->setBrush(QBrush(Qt::color1,
                      QBrush::FDiagPattern));
                  maskPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  maskPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);
                  //we need to draw again, because the border will not be drawn above (bug in Qt/E)
                  maskPainter->setPen(QPen(Qt::color1, 2));
                  maskPainter->setBrush(QBrush(Qt::color1, QBrush::NoBrush));
                  maskPainter->drawEllipse(gx, gy, 2 * R2, 2 * R2);
                  maskPainter->drawPie(qx, qy, 2 * R1, 2 * R1, w1 - 720, 1440);
                }
                
                // Strecke
                if(flightType == FAI_S || flightType == Dreieck_S)
                    targetPainter->setPen(QPen(QColor(50, 50, 50), 3));
                else
                    targetPainter->setPen(QPen(QColor(150, 0, 200), 3));

                maskPainter->setBrush(QBrush::SolidPattern);
                targetPainter->setBrush(QBrush::SolidPattern);
                
                maskPainter->setPen(QPen(Qt::color1, 3));
                targetPainter->drawLine(
                  glMapMatrix->map(wpList.at(loop - 1)->projP),
                  glMapMatrix->map(wpList.at(loop)->projP), true);
                maskPainter->drawLine(
                  glMapMatrix->map(wpList.at(loop - 1)->projP),
                  glMapMatrix->map(wpList.at(loop)->projP), true);
                break;

              default:
                // Kann noch Start und Landepunkt sein.

                // Linie von Startpunkt zum Aufgaben Beginn
                if(loop)
                  {
                    if(flightType == FAI_S || flightType == Dreieck_S)
                        targetPainter->setPen(QPen(QColor(150, 0, 200), 3));
                    else
                        targetPainter->setPen(QPen(Qt::blue, 2));

                    maskPainter->setPen(QPen(Qt::color1, 2));
                    targetPainter->drawLine(
                        glMapMatrix->map(wpList.at(loop - 1)->projP),
                        glMapMatrix->map(wpList.at(loop)->projP),true);
                    maskPainter->drawLine(
                        glMapMatrix->map(wpList.at(loop - 1)->projP),
                        glMapMatrix->map(wpList.at(loop)->projP),true);
                  }

                // Linie Um Start Lande Punkt
                targetPainter->setPen(QPen(Qt::black, 2));
                targetPainter->setBrush(QBrush::NoBrush);
                maskPainter->setPen(QPen(Qt::color1, 2));
                maskPainter->setBrush(QBrush::NoBrush);
                break;
            }
        }
    }

  // Strecke bei Start auf Schenkel
  if(flightType == FAI_S || flightType == Dreieck_S)
    {
      targetPainter->setPen(QPen(QColor(150, 0, 200), 3));
      maskPainter->setPen(QPen(Qt::color1, 3));
      targetPainter->drawLine(glMapMatrix->map(wpList.at(2)->projP),
          glMapMatrix->map(wpList.at(wpList.count() - 3)->projP),true);
      maskPainter->drawLine(glMapMatrix->map(wpList.at(2)->projP),
          glMapMatrix->map(wpList.at(wpList.count() - 3)->projP),true);
    }
}

int FlightTask::getPlannedPoints() const
{
  double pointFAI = 2.0;
  double pointNormal = 1.75;
  double pointZielS = 1.5;

  /*
   * Aufgabe vollständig erfüllt
   *        F: Punkte/km
   *        I: Index des Flugzeuges
   *        f & I noch abfragen !!!!
   */
  double F;
  switch(flightType)
    {
      case FlightTask::ZielS:
        F = pointZielS;
        break;
      case FlightTask::ZielR:
      case FlightTask::Dreieck:
      case FlightTask::Dreieck_S:
        F = pointNormal;
        break;
      case FlightTask::FAI:
      case FlightTask::FAI_S:
        F = pointFAI;
        break;
      default:
        F = 0.0;
    }

  return (int)((double)distance_task * F);
//  distance_wert = distance_task;

//  taskPoints = (distance_wert * F * 100) / gliderIndex * dmstMalus +
//                      (aussenlande * pointCancel * 100) / gliderIndex;
}

void FlightTask::checkWaypoints(QList<flightPoint> &route, const QString& /*gliderType*/)
{
  /*
   *   Überprüft, ob die Sektoren der Wendepunkte erreicht wurden
   *
   *   SOLLTE NOCHMALS ÜBERARBEITET WERDEN
   *
   */
  bool time_error = false;

  if(flightType == FlightTask::NotSet) return;

  if(!wpList.count()) return;

  int gliderIndex = 100, preTime = 0;

  double pointFAI = 2.0;
  double pointNormal = 1.75;
  double pointCancel = 1.0;
  double pointZielS = 1.5;
  double malusValue = 15.0;
  double sectorMalus = 0.1;

//  if(gliderType != 0L)
//    {
//      config->setGroup("GliderTypes");
//      gliderIndex = config->readNumEntry(gliderType, 100);
//    }
//  config->setGroup(0);

  gliderIndex = 100;
  
  for(unsigned int loop = 0; loop < route.count(); loop++)
    {
      if(loop && (route.at(loop)->time - preTime > 70))
          /*
           *           Zeitabstand zwischen Loggerpunkten ist zu gross!
           *                      (vgl. Code Sportif 3, Ziffer 1.9.2.1)
           */
          time_error = true;

      preTime = route.at(loop)->time;
    }

  unsigned int startIndex = 0, dummy = 0;

  for(unsigned int loop = 0; loop < wpList.count(); loop++)
    {
      double deltaAngle = 0.0, pointAngle = 0.0;
      dummy = 0;

      __sectorangle(loop, false);
      /*
       * Prüfung, ob Flugpunkte in den Sektoren liegen.
       *
       *      Ein Index 0 bei den Sektoren zeigt an, dass der Sektor
       *      _nicht_ erreicht wurde. Dies führt an Mitternacht zu
       *      einem möglichen Fehler ...
       */
      for(unsigned int pLoop = startIndex + 1; pLoop < route.count(); pLoop++)
        {
          if( wpList.at(loop)->projP == route.at(pLoop)->projP )
            {
              // Wir sind in allen Sektoren ...
              if(!wpList.at(loop)->sector1)
                  wpList.at(loop)->sector1 = route.at(pLoop)->time;

              if(!wpList.at(loop)->sector2)
                  wpList.at(loop)->sector2 = route.at(pLoop)->time;

              if(!wpList.at(loop)->sectorFAI)
                  wpList.at(loop)->sectorFAI = route.at(pLoop)->time;

              // ... daher ist ein Abbruch möglich!
              startIndex = pLoop;
              break;
            }
          else
            {
              if(dist(wpList.at(loop), route.at(pLoop)) <= 0.5)
                {
                  // Wir sind im kleinen Zylinder ...
                  if(!wpList.at(loop)->sector1)
                      wpList.at(loop)->sector1 = route.at(pLoop)->time;

                  if(!wpList.at(loop)->sector2)
                      wpList.at(loop)->sector2 = route.at(pLoop)->time;

                  if(!dummy)
                    {
                      startIndex = pLoop;
                      dummy = pLoop;
                    }
                }

              pointAngle = polar(
                  ( wpList.at(loop)->projP.x() - route.at(pLoop)->projP.x() ),
                  ( wpList.at(loop)->projP.y() - route.at(pLoop)->projP.y() ) );

              deltaAngle = sqrt( ( pointAngle - wpList.at(loop)->angle ) *
                                 ( pointAngle - wpList.at(loop)->angle ) );

              if(deltaAngle <= (0.25 * M_PI))
                {
                  // Wir sind im FAI-Sektor ...
                  if(!wpList.at(loop)->sectorFAI)
                      wpList.at(loop)->sectorFAI = route.at(pLoop)->time;

                  if(dist(wpList.at(loop), route.at(pLoop)) <= 3.0)
                    {
                      // ... und in Sektor 1 ...
                      if(!wpList.at(loop)->sector1)
                        {
                          wpList.at(loop)->sector1 = route.at(pLoop)->time;
                          // ... daher ist ein Abbruch möglich!
                          startIndex = pLoop;
                          break;
                        }

                    }
                }
              else if(deltaAngle <= (0.5 * M_PI))
                {
                  // "nur" in Sektor 2
                  if(!wpList.at(loop)->sector2)
                      wpList.at(loop)->sector2 = route.at(pLoop)->time;

                  if(!dummy)
                    {
                      startIndex = pLoop;
                      dummy = pLoop;
                    }
                }
            }
        }
    }

  /*
   * Überprüfen der Aufgabe
   */
  int faiCount = 0;
  unsigned int dmstCount = 0;
  double dmstMalus = 1.0, aussenlande = 0.0;
  bool home, stop = false;

  if (wpList.at(1)->sector1 == 0)
    {
      QMessageBox::information(0, QObject::tr("error"),
          QObject::tr("<qt>You have not reached the first waypoint of your task!</qt>"));
      return;
    }

  // Durchgehen der Wendepunkte
  for(unsigned int loop = 1; loop < wpList.count() - 2; loop++)
    {
      if(!stop)
        {
          if(wpList.at(loop)->sector1 != 0)
              dmstCount++;
          else if(wpList.at(loop)->sector2 != 0)
            {
              dmstMalus += sectorMalus;
              dmstCount++;
            }
          else
            {
              // Wendepunkt nicht erreicht!!
              if (loop == 2)
                {
                  QMessageBox::information(0, QObject::tr("error"),
                      QObject::tr("<qt>You have not reached the first waypoint of your task!</qt>"));
                  return;
                }
              /*
               * Wertung mit 1,5 Punkten, weil Punkt nicht erreicht
               */
              stop = true;
            }
        }

      if(wpList.at(loop)->sectorFAI != 0)
          faiCount++;
    }

  if(wpList.at(wpList.count() - 2)->sector1 == 0)
    {
      home = false;
      
      QMessageBox::critical(0, QObject::tr("error"),
          QObject::tr("<qt>You have not reached the last point of your task!</qt>"));

      if(dist(wpList.at(1 + dmstCount), route.last()) < 1.0)
        {
          // Landung auf letztem Wegpunkt
        }
      else
          // Außenlandung -- Wertung: + 1Punkt bis zur Außenlandung
          aussenlande = dist(wpList.at(1 + dmstCount), route.last());
    }
  else
    {
      // Zu Hause gelandet
      dmstCount++;
      faiCount++;
      home = true;
    }

// jetzt in __setDistance noch übernehmen
  distance_wert = 0;
  double F = 1;

  if(dmstCount != wpList.count() - 2)
    {
      if(home)
        {
          distance_wert = dist(wpList.at(wpList.count() - 1),
              wpList.at(dmstCount));
          for(unsigned int loop = 1; loop < 1 + dmstCount; loop++)
              distance_wert = distance_wert + wpList.at(loop)->distance;
        }
      else
        {
          for(unsigned int loop = 1; loop <= 1 + dmstCount; loop++)
              distance_wert = distance_wert + wpList.at(loop)->distance;
        }
    }
  else
    {
      /*
       * Aufgabe vollständig erfüllt
       *        F: Punkte/km
       *        I: Index des Flugzeuges
       *        f & I noch abfragen !!!!
       */
      switch(flightType)
        {
          case FlightTask::ZielS:
            F = pointZielS;
            break;
          case FlightTask::ZielR:
          case FlightTask::Dreieck:
          case FlightTask::Dreieck_S:
            F = pointNormal;
            break;
          case FlightTask::FAI:
          case FlightTask::FAI_S:
            F = pointFAI;
            break;
          default:
            F = 0.0;
        }
      distance_wert = distance_task;
    }

  taskPoints = (distance_wert * F * 100) / gliderIndex * dmstMalus +
                      (aussenlande * pointCancel * 100) / gliderIndex;

  if(!isOrig)
    {
      /*
       * Optimierter Flug: x% abziehen
       */
      taskPoints -= ( taskPoints * (malusValue / 100.0) );
    }

  if(time_error)
   {
     QMessageBox::critical(0, QObject::tr("wrong intervall"),
        QObject::tr("<qt>The time intervall between two points<BR>"
        "of the flight is more than 70 sec.!<BR>"
        "Due to Code Sportif 3, Nr. 1.9.2.1,<BR>"
        "the flight can not be valued!</qt>"));
   }
}

QString FlightTask::getTotalDistanceString() const
{
  if(flightType == FlightTask::NotSet)  return "--";

  QString distString;
  distString.sprintf("%.2f km", distance_total);

  return distString;
}


QString FlightTask::getTaskDistanceString() const
{
  if(flightType == FlightTask::NotSet)  return "--";

  /*QString distString;
  distString.sprintf("%.2f km", distance_task);

  return distString;*/
  return Distance::getText(distance_task*1000,true,2);
}

QString FlightTask::getPointsString() const
{
  if(flightType == FlightTask::NotSet)  return "--";

  int points1 = (int) taskPoints;
  if((int) ( (taskPoints - points1) * 10 ) > 5) points1++;

  QString pointString;
  pointString.sprintf("%d", points1);

  return pointString;
}

QRect FlightTask::getRect() const
{  
  return bBoxTask;
}

/**
 * Ovettakes a waypoint list. All single elements are deep copied.
 */
void FlightTask::setWaypointList(QList<wayPoint>& wpL)
{
  // Remove old content of list
  wpList.clear();

  // @AP: Make a deep copy from all elements of the new passed list

  for( uint i=0; i < wpL.count(); i++ )
    {
      wpList.append( new wayPoint(*wpL.at(i)) );
    }

  isOrig = false;

  __updateTask();
}

/**
 * updates the internal task data
 */
void FlightTask::__updateTask()
{
  __setWaypointType();
  __checkType();

  for(unsigned int loop = 0; loop < wpList.count(); loop++)
      __sectorangle(loop, false);
}

/**
 * @AP: Add a new waypoint to the list as deep copy
 */
void FlightTask::addWaypoint( wayPoint &newWP )
{
  wpList.append( new wayPoint(newWP) );
  isOrig = false;
  __updateTask();
}


void FlightTask::setPlanningType(int type)
{
  __planningType = type;
  __setWaypointType();
}
