//
//  Vessel.cpp
//  BasicVascularModeling
//
//  Created by Artur Klepaczko on 27.05.2014.
//  Copyright (c) 2014 Artur Klepaczko. All rights reserved.
//

#include "Vessel.h"
#include "Utils.h"
#include <math.h>

static int label = 0;

Vessel::Vessel(Point3D inlet, Point3D outlet, double flow, double pressure_in, double pressure_out) {
    
    this->_inlet = inlet;
    this->_outlet = outlet;
    this->_flow = flow;
    this->_pressure_in = pressure_in;
    this->_pressure_out = pressure_out;
    
    double delta_Pr = _pressure_in - _pressure_out;
    double length = distanceP2P(inlet, outlet);
    this->_radius = pow(8*_flow *BloodViscosityInPa_s*length / (M_PI*delta_Pr), 0.25);
    
    this->_daughter = NULL;
    this->_son = NULL;
    this->_parent = NULL;
    
    this->_isParent = false;
    this->_hasParent = false;
    
    this->ID = label;
    label++;
}

Vessel::Vessel(Point3D inlet, Point3D outlet, double flow, Vessel* parent, double pressure_out) {
    this->_inlet = inlet;
    this->_outlet = outlet;
    this->_flow = flow;
    this->_pressure_in = parent->getPressureOut();
    this->_pressure_out = pressure_out;
    
    double delta_Pr = _pressure_in - _pressure_out;
    double length = distanceP2P(inlet, outlet);
    this->_radius = pow(8*_flow*BloodViscosityInPa_s*length / (M_PI*delta_Pr), 0.25);
    
    this->_daughter = NULL;
    this->_son = NULL;
    this->_parent = parent;
    
    this->_isParent = false;
    this->_hasParent = true;
    
    this->ID = label;
    label++;
}


Vessel::Vessel(Vessel* original) {
    this->_inlet = original->getInlet();
    this->_outlet = original->getOutlet();
    this->_flow = original->getFlow();
    this->_pressure_in = original->getPressureIn();
    this->_pressure_out = original->getPressureOut();
    
    this->_radius = original->getRadius();
    
    this->_daughter = original->getDaughter();
    this->_son = original->getSon();
    this->_parent = original->getParent();
    
    this->_isParent = original->isParent();
    this->_hasParent = original->hasParent();
    
    this->ID = label;
    label++;
}

void Vessel::DeleteVesel(bool withSubtree) {
    clearParent();
    if (_isParent && withSubtree) {
        _son->DeleteVesel(withSubtree);
        _daughter->DeleteVesel(withSubtree);
    }
    delete this;
}

void Vessel::clearParent() {
    _parent = NULL;
    _hasParent = false;
}

Point3D Vessel::getInlet() {
    return _inlet;
}

Point3D Vessel::getOutlet() {
    return _outlet;
}

bool Vessel::hasParent() {
    return _hasParent;
}

bool Vessel::isParent() {
    return _isParent;
}

double Vessel::getVolume() {
    double volume = M_PI*_radius*_radius*distanceP2P(_inlet, _outlet);
    return volume;
}

void Vessel::setChildren(Vessel *son, Vessel *daughter) {
    _isParent = true;
    _son = son;
    _daughter = daughter;
    _son->setParent(this);
    _daughter->setParent(this);
}

void Vessel::accumulateFlow() {
    if (isParent()) {
        _son->accumulateFlow();
        _daughter->accumulateFlow();
        _flow = _son->getFlow() + _daughter->getFlow();
    }
    else return;
}
