#include <stdio.h>
#include "variables.h"

// type conversions
ConservVars
primitive2conserv (PrimitiveVars pv)
{
  ConservVars cv;
  cv.u1 = pv.p1 * pv.p2;
  cv.u2 = cv.u1 * pv.p3;
  cv.u3 = (1-pv.p1) * u3def;
  cv.u4 = cv.u3 * pv.p4;
  return cv;
};

PrimitiveVars
conserv2primitive (ConservVars cv)
{
  double phi = 1 - cv.u3/u3def;
  if (phi == 0) {
    perror("phi == 0");
    exit(EXIT_PHI_EQ_0);
  }
  double rg = cv.u1/phi;
  if (rg == 0) {
    perror("rg == 0");
    exit(EXIT_RG_EQ_0);
  }
  double ug = cv.u2/cv.u1;
  double ul; 
  if (phi == 1) {
    ul = 0;
  } else {
    ul = cv.u4/cv.u3;
  }
  return (PrimitiveVars) {phi, rg, ug, ul};
};

PrimitiveVars
num2primitive (double num)
{
  return (PrimitiveVars) {num, num, num, num};
};

ConservVars
num2conserv (double num)
{
  return (ConservVars) {num, num, num, num};
};

// output
int
sprintf_PrimitiveVars (char* str, PrimitiveVars vars)
{
  return sprintf(str, "%8.6E\t%8.6E\t%8.6E\t%8.6E", vars.p1, vars.p2, vars.p3, vars.p4);
}

int
sprintf_ConservVars (char* str, ConservVars vars)
{
  return sprintf(str, "%8.6E\t%8.6E\t%8.6E\t%8.6E", vars.u1, vars.u2, vars.u3, vars.u4);
}

// PrimiriveVars operator overloading
const PrimitiveVars
operator+ (PrimitiveVars v1, PrimitiveVars v2)
{
PrimitiveVars v3;
v3.p1 = v1.p1 + v2.p1;
v3.p2 = v1.p2 + v2.p2;
v3.p3 = v1.p3 + v2.p3;
v3.p4 = v1.p4 + v2.p4;
return v3;
}

const PrimitiveVars
operator- (PrimitiveVars v1, PrimitiveVars v2)
{
PrimitiveVars v3;
v3.p1 = v1.p1 - v2.p1;
v3.p2 = v1.p2 - v2.p2;
v3.p3 = v1.p3 - v2.p3;
v3.p4 = v1.p4 - v2.p4;
return v3;
}

const PrimitiveVars
operator* (PrimitiveVars v1, PrimitiveVars v2)
{
PrimitiveVars v3;
v3.p1 = v1.p1 * v2.p1;
v3.p2 = v1.p2 * v2.p2;
v3.p3 = v1.p3 * v2.p3;
v3.p4 = v1.p4 * v2.p4;
return v3;
}

const PrimitiveVars
operator/ (PrimitiveVars v1, PrimitiveVars v2)
{
PrimitiveVars v3;
v3.p1 = v1.p1 / v2.p1;
v3.p2 = v1.p2 / v2.p2;
v3.p3 = v1.p3 / v2.p3;
v3.p4 = v1.p4 / v2.p4;
return v3;
}

// Primitive-Number operator overloading
const PrimitiveVars
operator+ (PrimitiveVars vars, double num)
{
return vars + num2primitive(num);
}

const PrimitiveVars
operator+ (double num, PrimitiveVars vars)
{
return num2primitive(num) + vars;
}

const PrimitiveVars
operator- (PrimitiveVars vars, double num)
{
return vars - num2primitive(num);
}

const PrimitiveVars
operator- (double num, PrimitiveVars vars)
{
return num2primitive(num) - vars;
}

const PrimitiveVars
operator* (PrimitiveVars vars, double num)
{
return vars * num2primitive(num);
}

const PrimitiveVars
operator* (double num, PrimitiveVars vars)
{
return num2primitive(num) * vars;
}

const PrimitiveVars
operator/ (PrimitiveVars vars, double num)
{
return vars / num2primitive(num);
}

const PrimitiveVars
operator/ (double num, PrimitiveVars vars)
{
return num2primitive(num) / vars;
}

// ConservVars operator overloading
const ConservVars
operator+ (ConservVars v1, ConservVars v2)
{
ConservVars v3;
v3.u1 = v1.u1 + v2.u1;
v3.u2 = v1.u2 + v2.u2;
v3.u3 = v1.u3 + v2.u3;
v3.u4 = v1.u4 + v2.u4;
return v3;
}

const ConservVars
operator- (ConservVars v1, ConservVars v2)
{
ConservVars v3;
v3.u1 = v1.u1 - v2.u1;
v3.u2 = v1.u2 - v2.u2;
v3.u3 = v1.u3 - v2.u3;
v3.u4 = v1.u4 - v2.u4;
return v3;
}

const ConservVars
operator* (ConservVars v1, ConservVars v2)
{
ConservVars v3;
v3.u1 = v1.u1 * v2.u1;
v3.u2 = v1.u2 * v2.u2;
v3.u3 = v1.u3 * v2.u3;
v3.u4 = v1.u4 * v2.u4;
return v3;
}

const ConservVars
operator/ (ConservVars v1, ConservVars v2)
{
ConservVars v3;
v3.u1 = v1.u1 / v2.u1;
v3.u2 = v1.u2 / v2.u2;
v3.u3 = v1.u3 / v2.u3;
v3.u4 = v1.u4 / v2.u4;
return v3;
}

// Conserv-Number operator overloading
const ConservVars
operator+ (ConservVars vars, double num)
{
return vars + num2conserv(num);
}

const ConservVars
operator+ (double num, ConservVars vars)
{
return num2conserv(num) + vars;
}

const ConservVars
operator- (ConservVars vars, double num)
{
return vars - num2conserv(num);
}

const ConservVars
operator- (double num, ConservVars vars)
{
return num2conserv(num) - vars;
}

const ConservVars
operator* (ConservVars vars, double num)
{
return vars * num2conserv(num);
}

const ConservVars
operator* (double num, ConservVars vars)
{
return num2conserv(num) * vars;
}

const ConservVars
operator/ (ConservVars vars, double num)
{
return vars / num2conserv(num);
}

const ConservVars
operator/ (double num, ConservVars vars)
{
return num2conserv(num) / vars;
}