//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2015, University of Osnabrueck                                                                         //
//   All rights reserved.                                                                                               //
//                                                                                                                      //
//   Redistribution and use in source and binary forms, with or without modification, are permitted provided that the   //
//   following conditions are met:                                                                                      //
//                                                                                                                      //
//   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following//
//       disclaimer.                                                                                                    //
//                                                                                                                      //
//   2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       //
//       following disclaimer in the documentation and/or other materials provided with the distribution.               //
//                                                                                                                      //
//   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, //
//   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  //
//   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, //
//   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR    //
//   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  //
//   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE   //
//   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                           //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "ralans-propagation-loss-model.h"
#include "ns3/mobility-model.h"
#include "ns3/log.h"
//include boost for checking file extension
//#include <boost/filesystem.hpp>
//for using function according the MapFile attribute
#include "ns3/string.h"
//for using fuctions according the badNum attribute
#include "ns3/integer.h"
//for using fuctions according the threshold attribute
#include "ns3/double.h"
//for using fuctions according the boolean attribute
#include "ns3/boolean.h"

NS_LOG_COMPONENT_DEFINE ("RaLaNSPropagationLossModel");

namespace ns3 {

	/* ... */

	NS_OBJECT_ENSURE_REGISTERED (RaLaNSPropagationLossModel);

	RaLaNSPropagationLossModel::RaLaNSPropagationLossModel () : PropagationLossModel ()
	{

	}

	RaLaNSPropagationLossModel::~RaLaNSPropagationLossModel ()
	{

	}

	TypeId RaLaNSPropagationLossModel::GetTypeId (void) {
		static TypeId tid = TypeId ("ns3::RaLaNSPropagationLossModel")
			.SetParent<PropagationLossModel> ()
			.AddConstructor<RaLaNSPropagationLossModel> ()
			.AddAttribute ("listInterpolationNum", 
					"This value decides how many points are interpolated for lists",
					IntegerValue (LISTINTERPOLATIONNUM),
					MakeIntegerAccessor (&RaLaNSPropagationLossModel::SetListInterpolationNum), 
					MakeIntegerChecker<int> ())
			.AddAttribute ("badNum", 
					"This value is for the interpolation calculation."
					"In the interpolation process it can happen that there are some bad signals."
					"Bad signals are signal with a value smaller or equal noSignal."
					"With this parameter you can exclude some bad signals up to a maximum of bad signals"
					"which is specified by this parameter."
					"This is to prevent very low signal values," 
					"although there is just 1 or 2 bad signal values in the interpolation process."
					"The default value is BADNUM. A negative value or 0 does not have any affect."
					"It is recommended to use values lower than 4 for areas and lower than 16 for cubics.",
					IntegerValue (BADNUM),
					MakeIntegerAccessor (&RaLaNSPropagationLossModel::SetBadNum),                         
					MakeIntegerChecker<int> ())
			.AddAttribute ("threshold", 
					"the maximum value for the distance between a mobility model "                   
					"and the nearest point to that mobility model for a valid signal calculation. "      
					"This value will be used, "
					"when the nearest point to mobilitymodel is calculated " 
					"and the distance is checked. " 
					"When the distance is bigger than the one setted here, "
					"an error will be thrown and the signal will be set to noSignal. "
					"The default value is THRESHOLD",
					DoubleValue (THRESHOLD),
					MakeDoubleAccessor (&RaLaNSPropagationLossModel::SetThreshold), 
					MakeDoubleChecker<double> ())
			.AddAttribute ("noSignal", 
					"NoSignal is the signal value for cases, in which there is no signal. "
					"This signal value will be set if it is influenced by the threshold. "
					"If the point is too far away, the noSignal value will be returned. "
					"If the point is outside the grid(area or cubic), "
					"the nearest point in the grid will be interpolated with noSignal "
					"in relation to the threshold value."
					"The default value is NOSIGNAL",
					DoubleValue (NOSIGNAL), 
					MakeDoubleAccessor (&RaLaNSPropagationLossModel::SetNoSignal),                         
					MakeDoubleChecker<double> ())
			.AddAttribute ("interpolate", 
					"if true the interpolate option will be used, if false not." 
					" The interpolation is only possible for areas and cubics."
					" The default value is true.",
					BooleanValue (true),                                                                   
					MakeBooleanAccessor (&RaLaNSPropagationLossModel::SetInterpolate),
					MakeBooleanChecker ())
			.AddAttribute ( "mapFile",
					"Path to the file that contains the propagation information. "
					"The file has to be a zip or txt file. "
					"If the file is a zip file, "
					"the zip file will be extracted using unzip "
					"into a directory with the same name as the zip file has"
					" in the same directory as the zip file is.",
					StringValue ("coverage/example.txt"),
					MakeStringAccessor (&RaLaNSPropagationLossModel::SetFile),
					MakeStringChecker ());
		return tid;
	}

	bool RaLaNSPropagationLossModel::GetInterpolate() const{
		return this->raLaNSAlone.GetInterpolate();
	}

	void RaLaNSPropagationLossModel::SetInterpolate(bool interpolate){
		this->raLaNSAlone.SetInterpolate(interpolate);
	}

	double RaLaNSPropagationLossModel::GetNoSignal() const{
		return this->raLaNSAlone.GetNoSignal();
	}

	void RaLaNSPropagationLossModel::SetNoSignal(double noSignal){
		this->raLaNSAlone.SetNoSignal(noSignal);
	}

	double RaLaNSPropagationLossModel::GetThreshold() const{
		return this->raLaNSAlone.GetThreshold();
	}

	void RaLaNSPropagationLossModel::SetThreshold(double threshold){
		this->raLaNSAlone.SetThreshold(threshold);
	}

	void RaLaNSPropagationLossModel::SetBadNum(int badNum){
		this->raLaNSAlone.SetBadNum(badNum);
	}

	int RaLaNSPropagationLossModel::GetBadNum() const{
		return this->raLaNSAlone.GetBadNum();
	}

	std::string RaLaNSPropagationLossModel::GetFile() const{
		return this->raLaNSAlone.GetFile();
	}

	void RaLaNSPropagationLossModel::SetFile (std::string filename) {
		this->raLaNSAlone.SetFile(filename);
	}

	int RaLaNSPropagationLossModel::GetListInterpolationNum() const{
		return this->raLaNSAlone.GetListInterpolationNum();
	}

	void RaLaNSPropagationLossModel::SetListInterpolationNum(int listInterpolationNum){
		this->raLaNSAlone.SetListInterpolationNum(listInterpolationNum);
	}

	std::vector<double> RaLaNSPropagationLossModel::transformToVec(const Ptr<MobilityModel> &point) const{

		std::vector<double> vPoint(LENPOINT);

		vPoint[XAXIS] = point->GetPosition().x;
		vPoint[YAXIS] = point->GetPosition().y;
		vPoint[ZAXIS] = point->GetPosition().z;

		return vPoint;
	}

	double RaLaNSPropagationLossModel::DoCalcRxPower (double txPowerDbm,
			Ptr<MobilityModel> a,
			Ptr<MobilityModel> b) const
	{

		return txPowerDbm + raLaNSAlone.DoCalc(this->transformToVec(a),this->transformToVec(b));
	}

	int64_t RaLaNSPropagationLossModel::DoAssignStreams (int64_t stream)
	{
		return 0;
	}
}
