/***************************************************************************
                          speed.cpp  -  description
                             -------------------
    begin                : Sat Jul 20 2002
    copyright            : (C) 2002 by Andre Somers
    email                : andre@kflog.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 <cmath>
#include "speed.h"

Speed::Speed(){
  _speed=0;
  _isValid=false;
  changed();
}

Speed::Speed(double Mps){
  _speed=Mps;
  _isValid=true;
  changed();
}

Speed::~Speed(){
}

void Speed::setVerticalUnit(speedUnit unit){
  _verticalUnit=unit;
}

void Speed::setHorizontalUnit(speedUnit unit){
  _horizontalUnit=unit;
}

Speed::speedUnit Speed::getVerticalUnit(){
  return _verticalUnit;
}

Speed::speedUnit Speed::getHorizontalUnit(){
  return _horizontalUnit;
}

/** Set speed in meters per second. */
void Speed::setMps(double speed){
  _speed=speed;
  _isValid=true;
  changed();
}

/** Set speed in Kilometers per hour */
void Speed::setKph(double speed){
  _speed=speed/toKph;
  _isValid=true;
  changed();
}

/** Set speed in knots */
void Speed::setKnot(double speed){
  _speed=speed/toKnot;
  _isValid=true;
  changed();
}

/** Set speed in Nautical miles per hour */
void Speed::setMph(double speed){
  _speed=speed/toMph;
  _isValid=true;
  changed();
}

/** Set speed in feet per minute */
void Speed::setFpm(double speed){
  _speed=speed/toFpm;
  _isValid=true;
  changed();
}

/** Get speed in Meters per Second */
double Speed::getMps() const {
  return (_speed);
}

/** Get speed in Kilometers per hour */
double Speed::getKph() const {
  return (_speed*toKph);
}

/** Get speed in Knots. */
double Speed::getKnots() const {
  return (_speed*toKnot);
}

/** Get speed in Nautical Miles per hour */
double Speed::getMph() const {
  return (_speed*toMph);
}

/** Get speed in feet per minute */
double Speed::getFpm() const {
  return (_speed*toFpm);
}

/** + operator for speed. */
Speed Speed::operator + (const Speed& x) const {
  return Speed(x._speed + _speed);
}

/** - operator for speed. */
Speed Speed::operator - (const Speed& x) const {
  return Speed(_speed - x._speed);
}

/** - operator for speed. */
Speed operator - (double left, const Speed& right) {
  return Speed(left - right.getMps());
}

/** + operator for speed. */
Speed operator + (double left, const Speed& right) {
  return Speed(left + right.getMps());
}

/** * operator for speed. */
Speed operator * (double left, const Speed& right) {
  return Speed(left * right.getMps());
}

/** / operator for speed. */
double Speed::operator / (const Speed& x) const {
  return _speed / x._speed;
}

/** * operator for speed. */
double Speed::operator * (const Speed& x) const {
  return _speed * x._speed;
}

/** == operator for Speed */
bool Speed::operator == (const Speed& x) const {
  return (x._speed==_speed);
}

/** != operator for Speed */
bool Speed::operator != (const Speed& x) const {
  return (x._speed !=_speed);
}

/** - prefix operator for speed */
Speed Speed::operator - () const
{
  return Speed (-_speed);
}

/** Returns a formatted string for the default horizontal unit-setting. */
QString Speed::getTextHorizontal(bool withUnit, uint precision) const
{
  QString result, unit;
  double speed;

  switch (_horizontalUnit) {
  case knots:
    unit="Knt";
    speed=getKnots();
    break;
  case milesPerHour:
    unit="Mph";
    speed=getMph();
    break;
  case metersPerSecond:
    unit="m/s";
    speed=getMps();
    break;
  case kilometersPerHour:
    unit="Km/h";
    speed=getKph();
    break;
  case feetPerMinute:
    unit="Fpm";
    speed=getFpm();
    break;
  default:
    unit="Kph";
    speed=getKph();
  }

  QCString prec;
  prec.setNum(precision);
  if (withUnit) {
    result.sprintf("%1." + prec + "f %s",speed,unit.latin1());
  } else {
    result.sprintf("%1." + prec + "f",speed);
  }
  return result;

}

/** Returns a formatted string for the default vertical speed units. */
QString Speed::getTextVertical(bool withUnit, uint precision) const
{
  QString result, unit;
  double speed;

  switch (_verticalUnit) {
  case knots:
    unit="Knt";
    speed=getKnots();
    break;
  case milesPerHour:
    unit="Mph";
    speed=getMph();
    break;
  case metersPerSecond:
    unit="m/s";
    speed=getMps();
    break;
  case kilometersPerHour:
    unit="Km/h";
    speed=getKph();
    break;
  case feetPerMinute:
    unit="Fpm";
    speed=getFpm();
    break;
  default:
    unit="m/s";
    speed=getMps();
  }

  QCString prec;
  prec.setNum(precision);
  double round=0.5/(10^precision);
  
  if ( fabs(speed) < round ) speed=0.0;
  
  if (withUnit) {
    result.sprintf("%1." + prec + "f %s",speed,unit.latin1());
  } else {
    result.sprintf("%1." + prec + "f",speed);
  }
  return result;
}

/** Set speed in selected horizontal unit. */
void Speed::setValueHorizontal(double speed)
{
  switch (_horizontalUnit)
  {
  case knots:
    setKnot(speed);
    break;
  case milesPerHour:
    setMph(speed);
    break;
  case metersPerSecond:
    setMps(speed);
    break;
  case kilometersPerHour:
    setKph(speed);
    break;
  case feetPerMinute:
    setFpm(speed);
    break;
  default:
    setKph(speed);
  }
}

/** Set speed in selected vertical unit. */
void Speed::setValueVertical(double speed)
{
  switch (_verticalUnit)
  {
  case knots:
    setKnot(speed);
    break;
  case milesPerHour:
    setMph(speed);
    break;
  case metersPerSecond:
    setMps(speed);
    break;
  case kilometersPerHour:
    setKph(speed);
    break;
  case feetPerMinute:
    setFpm(speed);
    break;
  default:
    setMps(speed);
    break;
  }
}

void Speed::changed()
{
  // @AP Note: we have negative speed values in the variometer
  // culculation. Setting to zero is not a good idea.

  // speed should not be less than 0
  // if (_speed<0) _speed=0;
}

Speed::speedUnit Speed::_horizontalUnit=kilometersPerHour;
Speed::speedUnit Speed::_verticalUnit=metersPerSecond;
