#include <stdio.h>
#include <math.h>
#include "complex.h"

// Constructors
Complex complex_new(double re, double im) {
    Complex z;
    z.re = re;
    z.im = im;
    return z;
}

// Add
Complex complex_add(Complex a, Complex b) {
    return complex_new(a.re + b.re, a.im + b.im);
}

// Subtract
Complex complex_sub(Complex a, Complex b) {
    return complex_new(a.re - b.re, a.im - b.im);
}

// Multiply
Complex complex_mul(Complex a, Complex b) {
    return complex_new(a.re * b.re - a.im * b.im,
        a.re * b.im + a.im * b.re);
}

// Divide
Complex complex_div(Complex a, Complex b) {
    double denom = b.re * b.re + b.im * b.im;
    return complex_new((a.re * b.re + a.im * b.im) / denom,
        (a.im * b.re - a.re * b.im) / denom);
}

// Scalar multiply
Complex complex_scale(Complex a, double alpha) {
    return complex_new(a.re * alpha, a.im * alpha);
}

// Conjugate
Complex complex_conjugate(Complex a) {
    return complex_new(a.re, -a.im);
}

// Reciprocal
Complex complex_reciprocal(Complex a) {
    double scale = a.re * a.re + a.im * a.im;
    return complex_new(a.re / scale, -a.im / scale);
}

// Magnitude (faster than hypot)
double complex_abs(Complex a) {
    return sqrt(a.re * a.re + a.im * a.im);
}

// Phase
double complex_phase(Complex a) {
    return atan2(a.im, a.re);
}

// Exponential
Complex complex_exp(Complex a) {
    double exp_re = exp(a.re);
    return complex_new(exp_re * cos(a.im),
        exp_re * sin(a.im));
}

// Sine
Complex complex_sin(Complex a) {
    return complex_new(sin(a.re) * cosh(a.im),
        cos(a.re) * sinh(a.im));
}

// Cosine
Complex complex_cos(Complex a) {
    return complex_new(cos(a.re) * cosh(a.im),
        -sin(a.re) * sinh(a.im));
}

// Tangent
Complex complex_tan(Complex a) {
    Complex s = complex_sin(a);
    Complex c = complex_cos(a);
    return complex_div(s, c);
}

// Print function
void complex_print(Complex a) {
    if (a.im == 0)
        printf("%g", a.re);
    else if (a.re == 0)
        printf("%gi", a.im);
    else if (a.im < 0)
        printf("%g - %gi", a.re, -a.im);
    else
        printf("%g + %gi", a.re, a.im);
}
