/*
 * AXMIspAeValue.cpp
 * AE演算用クラス
 *
 */
#include <iostream>
#include <iomanip>

#include "AXMIspAeValue.hpp"

#ifndef PARASOFT_CPPTEST
using namespace std;
#endif

AXMIspAePercent::AXMIspAePercent() {
  AePercent.b = 0U;
}

AXMIspAePercent::~AXMIspAePercent() {
#ifndef PARASOFT_CPPTEST
  #ifndef COUT_DEBUG
  cout << "AXMIspAePercent::デストラクタ" << endl;
  #endif
#endif
}

void AXMIspAePercent::set(USHORT percent)
    {
  AePercent.b = percent;
}

USHORT AXMIspAePercent::get(void) const
    {
  return AePercent.b;
}

AXMIspAePercent& AXMIspAePercent::operator=(const short& obj)
    {
  set(obj);
  return *this;
}

void AXMIspAePercent::print() const {
#ifndef PARASOFT_CPPTEST
  short tmp, a, b;		// klockwork 指摘に対応
  tmp = AePercent.b;
  a = b = 0;	// klockwork 指摘に対応		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）

  while (tmp >= 100) {		// ※コンパイラ都合によりenumから数値に変更（_HUNDRED -> 100）
    ++a;
    tmp -= 100;		// ※コンパイラ都合によりenumから数値に変更（_HUNDRED -> 100）
  }
  while (tmp >= 10) {		// ※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
    ++b;
    tmp -= 10;		// ※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
  }
  if (tmp == 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    //　小数点第2位が0の場合
  #ifndef COUT_DEBUG
    cout << dec << a;
    cout << ".";
    cout << dec << b << endl;
  #endif
  } else {
  #ifndef COUT_DEBUG
    cout << dec << a;
    cout << ".";
    cout << dec << b;
    cout << dec << tmp << endl;
  #endif
  }
#endif
}

AXMIspAeValue::AXMIspAeValue() {
  set(0, 0);		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
}

AXMIspAeValue::~AXMIspAeValue() {
}

AXMIspAeValue AXMIspAeValue::operator+(const AXMIspAeValue& obj) {
  AXMIspAeValue tmp;

  tmp.set(conv2Long() + obj.conv2Long());
  return tmp;
}

AXMIspAeValue& AXMIspAeValue::operator+=(const AXMIspAeValue& obj)	// +=演算子オーバーロード
    {
  set(conv2Long() + obj.conv2Long());
  return *this;
}

AXMIspAeValue AXMIspAeValue::operator-(const AXMIspAeValue& obj) 	// -演算子オーバーロード
    {
  AXMIspAeValue tmp;

  tmp.set(conv2Long() - obj.conv2Long());
  return tmp;
}

AXMIspAeValue& AXMIspAeValue::operator-=(const AXMIspAeValue& obj)	// -=演算子オーバーロード
    {
  set(conv2Long() - obj.conv2Long());
  return *this;

}

AXMIspAeValue AXMIspAeValue::operator*(const AXMIspAePercent& obj) {
  AXMIspAeValue tmp;
  long valueLong = conv2Long();  // long ← 整数部×１０＋小数部
      // 4-2-2 不感帯の処理 閾値を求める

  valueLong = (obj.get() * valueLong);
  if (valueLong >= 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    valueLong = (valueLong + ((100 + 1) / 2)) / 100;	// 少数第２位を四捨五入		※コンパイラ都合によりenumから数値に変更（_ONE -> 1, _TWO -> 2, _HUNDRED -> 100）
  } else {
    valueLong = (valueLong - ((100 + 1) / 2)) / 100;	// 少数第２位を四捨五入		※コンパイラ都合によりenumから数値に変更（_ONE -> 1, _TWO -> 2, _HUNDRED -> 100）
  }
  tmp.set(valueLong);
  return tmp;

}

AXMIspAeValue AXMIspAeValue::operator*(const AXMIspAeValue& obj) 	// *演算子オーバーロード
    {
  // AXMIspAeValue型×AXMIspAeValue型
  //　10倍×10倍なので変換時は2桁減らす
  USHORT intval = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  USHORT fracval = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  AXMIspAeValue tmp;
  long longval = conv2Long() * obj.conv2Long();  // long ← 整数部×１０＋小数部

  bool signFlag = (longval < 0);		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）

  if (signFlag) {
    longval = -longval;  // 符号を反転
  }
  if (longval > (AE_MAX_VALUE * 10)) {
    longval = (AE_MAX_VALUE * 10);
  }

  while (longval >= 10000L) {  // 10,000以上の場合		※コンパイラ都合によりenumから数値に変更（_TEN_THOUSAND -> 10000L）
    intval += 100;				//　100の位をUp		※コンパイラ都合によりenumから数値に変更（_HANDRED -> 100）
    longval -= 10000L;		// 10,000減算		※コンパイラ都合によりenumから数値に変更（_TEN_THOUSAND -> 10000L）
  }
  while (longval >= 1000L) {	// 1,000以上の場合		※コンパイラ都合によりenumから数値に変更（_THOUSAND -> 1000L）
    intval += 10;				//　10の位をUp		※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
    longval -= 1000L;		// 1,000減算		※コンパイラ都合によりenumから数値に変更（_THOUSAND -> 1000L）
  }
  while (longval >= 100) {  // 100以上の場合		※コンパイラ都合によりenumから数値に変更（_HANDRED -> 100）
    intval += 1;		//　10の位をUp		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
    longval -= 100;		// 100減算		※コンパイラ都合によりenumから数値に変更（_HANDRED -> 100）
  }
  while (longval >= 10) {		// 10以上の場合		※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
    fracval += 1;		// 　1の位をUp		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
    longval -= 10;			// 10減算		※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
  }

  tmp.AeVal.sign = signFlag;
  tmp.AeVal.FILLER = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  tmp.AeVal.intval = intval;
  tmp.AeVal.fracval = fracval;
  return tmp;
}

AXMIspAeValue AXMIspAeValue::operator/(const USHORT& obj) {
  AXMIspAeValue tmp;
  long valueLong = conv2Long();  // long ← 整数部×１０＋小数部

  if (obj > 0) {		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
    tmp.set(valueLong / obj);
  }
  return tmp;

}

bool AXMIspAeValue::operator>(const AXMIspAeValue& obj)	 // >演算子オーバーロード
    {
  return (conv2Long() > obj.conv2Long());
}

bool AXMIspAeValue::operator>=(const AXMIspAeValue& obj) 			// >=演算子オーバーロード
    {
  return (conv2Long() >= obj.conv2Long());
}

bool AXMIspAeValue::operator<(const AXMIspAeValue& obj) 				// <演算子オーバーロード
    {
  return (conv2Long() < obj.conv2Long());
}

bool AXMIspAeValue::operator<=(const AXMIspAeValue& obj) 			// <=演算子オーバーロード
    {
  return (conv2Long() <= obj.conv2Long());
}

bool AXMIspAeValue::operator==(const AXMIspAeValue& obj) 			// ==演算子オーバーロード
    {
  return (conv2Long() == obj.conv2Long());
}

void AXMIspAeValue::set(USHORT intval, USHORT fracval) {
  AeVal.sign = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  AeVal.FILLER = 0;		// klocwork		※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  AeVal.intval = intval & MASK_8BIT;
  AeVal.fracval = (fracval > 9) ? 9 : fracval;		// ※コンパイラ都合によりenumから数値に変更（_NINE -> 9）
}

void AXMIspAeValue::set(LONG longval) {
  USHORT intval = 0;		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）
  bool signFlag = (longval < 0);		// ※コンパイラ都合によりenumから数値に変更（_ZERO -> 0）

  if (signFlag) {
    longval = -longval;  // 符号を反転
  }
  if (longval > AE_MAX_VALUE) {
    longval = AE_MAX_VALUE;
  }
  while (longval >= 1000L) {	// 1000以上の場合		※コンパイラ都合によりenumから数値に変更（_THOUSAND -> 1000L）
    intval += 100;  //　100の位をUp		※コンパイラ都合によりenumから数値に変更（_HUNDRED -> 100）
    longval -= 1000L;		// 1000減算		※コンパイラ都合によりenumから数値に変更（_THOUSAND -> 1000L）
  }
  while (longval >= 100) {  // 100以上の場合		※コンパイラ都合によりenumから数値に変更（_HUNDRED -> 100）
    intval += 10;		//　10の位をUp				※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
    longval -= 100;		// 100減算		※コンパイラ都合によりenumから数値に変更（_HUNDRED -> 100）
  }
  while (longval >= 10) {		// 10以上の場合		※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
    intval += 1;		// 　1の位をUp		※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
    longval -= 10;			// 10減算		※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
  }
  AeVal.sign = signFlag;
  AeVal.intval = intval;
  AeVal.fracval = longval;

}

AXMIspAeValue& AXMIspAeValue::operator=(const long& obj) {
  set(obj);
  return *this;
}  // =演算子オーバーロード

SHORT AXMIspAeValue::get(void) const {
  short temp = ((AeVal.intval << 4) | AeVal.fracval);		// ※コンパイラ都合によりenumから数値に変更（_FOUR -> 4）
  if (AeVal.sign == 1) {		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
    temp = -temp;
  }
  return temp;
}

LONG AXMIspAeValue::conv2Long(void) const {
  long longValue = static_cast<long>(AeVal.intval * 10 + AeVal.fracval);		// ※コンパイラ都合によりenumから数値に変更（_TEN -> 10）
  if (AeVal.sign == 1) {		// ※コンパイラ都合によりenumから数値に変更（_ONE -> 1）
    // 負の値
    longValue = -longValue;
  }
  return longValue;
}

USHORT AXMIspAeValue::getIntval(void) const {
  return AeVal.intval;
}

USHORT AXMIspAeValue::getFracval(void) const {
  return AeVal.fracval;
}

USHORT AXMIspAeValue::getSign(void) const {
  return AeVal.sign;
}

void AXMIspAeValue::print() const {
#ifndef PARASOFT_CPPTEST
  if (getSign()) {
  #ifndef COUT_DEBUG
    cout << "-";
  #endif
  }
  #ifndef COUT_DEBUG
  cout << dec << getIntval();
  cout << ".";
  cout << dec << getFracval() << endl;
  #endif
#endif
}
