#ifndef __MATLAB_H__
#define __MATLAB_H__

#include <client.h>
#include <vector>

int matlab_use_other (const char *forthis, const char *this_)
{
	char from[255], to[255];
	snprintf(from, 255, "lib%s_mcr/lib%s/%s.m", this_, this_, this_);
	/*snprintf(to, 255, "lib%s_mcr", forthis);
	mkdir(to, 0755);
	snprintf(to, 255, "lib%s_mcr/lib%s", forthis, forthis);
	mkdir(to, 0755);*/
	snprintf(to, 255, "lib%s_mcr/lib%s/%s.m", forthis, forthis, this_);
	if (access(to, R_OK) == 0)
		return 0;
	int ret = rename(from, to);
	if (ret == -1)
		perror("matlab_use_other");
	return ret;
}

// Adds automatic type conversion to mwArray
class myMwArray : public mwArray
{
	private:
		static const bool has_bug = true;
		mutable std::string strTmp;
		
		void resize (int n, int m)
		{
			// This is what the constructor of mwArray does.
			if (mclGetMatrix((void**)&m_pa, n, m, mxDOUBLE_CLASS, mxREAL) == MCLCPP_ERR)
				mwException::raise_error(); 
			validate();
		}

	public:
		myMwArray()
		{
		}

		myMwArray(double d) : mwArray(d)
		{
		}

		myMwArray(int i) : mwArray(i)
		{
		}

		myMwArray(const std::string &s) : mwArray(s.c_str())
		{
		}

		myMwArray(const myVector &v)
		{
			int n = v.size();
			resize(n, 1);

			double *moo = (double *)malloc(sizeof(double)*n);
			int k = 0;
			for (int i=0;i<n;i++)
				moo[k++] = v[i];
			SetData(moo, n);
		}

		myMwArray(const myMatrix &mat)
		{
			int m = mat.size();
			int n = mat[0].size();
			resize(m, n);

			double *moo = (double *)malloc(sizeof(double)*m*n);
			int k = 0;

			/*if (has_bug)
			{
				for (int j=0;j<n;j++)
					for (int i;i<m;i++)
						moo[k++] = mat[i][j];
			}
			else
			{*/
				for (int i=0;i<m;i++)
					for (int j=0;j<n;j++)
						moo[k++] = mat[i][j];
			//}
			SetData(moo, m*n);
		}

		operator myVector() const
		{
			mwArray arr = GetDimensions();
			int size[2];
			arr.GetData(size, 2);

			double *d = (double *)malloc(sizeof(double)*size[0]);
			GetData(d, size[0]);

			myVector ret(size[0]);
			int k = 0;
			for (int i=0;i<size[0];i++)
				ret[i] = d[k++];
			return ret;
		}

		operator myMatrix() const
		{
			mwArray arr = GetDimensions();
			int size[2];
			arr.GetData(size, 2);

			double *d = (double *)malloc(sizeof(double)*size[0]*size[1]);
			GetData(d, size[0]*size[1]);

			myMatrix ret;
			ret.resize(size[0]);

			for (int i=0;i<ret.size();i++)
				ret[i].resize(size[1]);

			int k = 0;

			/* 
			 * In some MATLAB versions the devs mixed up the indices, this
			 * can be fixed by swapping the inner and the outer loop.
			 */
			if (has_bug)
			{
				for (int j=0;j<ret[0].size();j++)
					for (int i=0;i<ret.size();i++)
						ret[i][j] = d[k++];
			}
			else
			{
				for (int i=0;i<ret.size();i++)
					for (int j=0;j<ret[0].size();j++)
						ret[i][j] = d[k++];
			}

			return ret;
		}

		operator const std::string&() const
		{
			char_buffer* p = array_ref_to_string(m_pa);
			if (!p)
				mwException::raise_error();
			return strTmp=(const char *)p->get_buffer();
		}
};

#endif
