#ifndef V2_H
# define V2_H

#include "gpk_std.h"
#include "gpklib/ieee754.h"
#include <iostream>
using namespace std;

PLAIN_C_START

typedef struct	{double d[2]; BOOL ok;} v2;

void v2constr(v2 *p);
BOOL v2badmat(v2 a);
double v2max(v2 a);
double v2norm_2(v2 a);
double v2norm(v2 a);
v2 v2add(v2 a, v2 b);
v2 v2sub(v2 a, v2 b);
v2 v2smult(v2 a, double sb);
v2 v2zero();
/* void v2print(FILE *fp, v2 a); */

#ifdef __cplusplus
PLAIN_C_END

class ltransform;

struct vector_space	{
	vector_space() : name(0), tobase(0) {}
	vector_space(C vector_space& a);
	vector_space& operator=(C vector_space&);
	vector_space(C char *nm, C ltransform *tob=0);
	vector_space(C ltransform *tob);
	~vector_space();
	C static vector_space bad;
	char *name;
	C ltransform *tobase;
	vector_space& set_name(C char *nm);
	vector_space& set_transform(C ltransform *tob) {tobase=tob; return *this;}
	static C vector_space* vseq(C vector_space *a, C vector_space *b)
		{ return (a==b || b==0) ? a : (a==0 ? b : &vector_space::bad);}
	static BOOL vseQ(C vector_space *a, C vector_space *b);
	static BOOL vsok(C vector_space *a) { return a!=&vector_space::bad;}
	};



class vector2 {
	double d[2];
	C vector_space *vs;

	protected:
	void load(double a, double b, C vector_space *ss=0)	{d[0]=a; d[1]=b; vs=ss;}

	public:
	double operator()(int i) C	{return d[i];}
	vector2(C vector2& a);
	vector2& operator=(C vector2& a);
	vector2();
	vector2(double a00, double a01, C vector_space *ss=0);

	BOOL badmat() C	{return !vector_space::vsok(vs);}
	BOOL ok() C	{return vector_space::vsok(vs);}

	double norm() C;
	double norm_2() C	{return d[0]*d[0]+d[1]*d[1];}
	double max() C;
	friend vector2 operator+(C vector2& a, C vector2& b);
	friend vector2 operator-(C vector2& a, C vector2& b);
	vector2 operator-() C;
	friend vector2 operator*(double a, C vector2& b);
	friend vector2 operator*(C vector2& a, double b);
	friend vector2 operator/(C vector2& a, double b);
	friend ostream& operator<<(ostream& s, C vector2& a);
	vector2& operator*=(double f);
	vector2& operator/=(double f);
	vector2& operator+=(C vector2& a);
	vector2& operator-=(C vector2& a);
	C vector_space *space() C {return vs;}
	C vector2 ns() C	{return vector2(d[0], d[1]);}
	vector2& set_space(C vector_space *s) {vs = s; return *this;}

	static vector2 unitvec(double angle);
	};

inline vector2::vector2(C vector2& a)
: vs(a.vs) {d[0] = a.d[0]; d[1] = a.d[1];}

inline vector2& vector2::operator=(C vector2& a)
{vs=a.vs; d[0]=a.d[0]; d[1]=a.d[1]; return *this;}

inline vector2::vector2(double a00, double a01, C vector_space *ss)
: vs(ss) {d[0]=a00; d[1]=a01;}


inline vector2 operator+(C vector2& a, C vector2& b)
{return vector2(a.d[0]+b.d[0], a.d[1]+b.d[1], vector_space::vseq(a.vs, b.vs));}

inline vector2 operator-(C vector2& a, C vector2& b)
{return vector2(a.d[0]-b.d[0], a.d[1]-b.d[1], vector_space::vseq(a.vs, b.vs));}

inline vector2 vector2::operator-() C
	{return vector2(-d[0], -d[1], vs);}

inline vector2 operator*(double a, C vector2& b)
	{return vector2(a*b.d[0], a*b.d[1], b.vs);}

inline vector2 operator*(C vector2& a, double b)
	{return vector2(a.d[0]*b, a.d[1]*b, a.vs);}

inline vector2 operator/(C vector2& a, double b)
	{return vector2(a.d[0]/b, a.d[1]/b, a.vs);}

inline vector2& vector2::operator*=(double f)
{ d[0] *= f; d[1]*=f; return *this; }

inline vector2& vector2::operator/=(double f)
{ d[0] /= f; d[1] /= f; return *this; }

ostream& operator<<(ostream& s, C vector2& a);

inline double dist(C vector2& a)	{return a.norm();}
double angle(C vector2& a);

inline double dot(C vector2& a, C vector2& b) {return a(0)*b(0)+a(1)*b(1);}

vector2 normalize(C vector2& a);

int finite(C vector2& a);

#endif
#endif
