import { convertOtherProperties } from './utils.js';

class Species {
  #keys = [
    'name',
    'molecular_weight',
    'constant_concentration',
    'constant_mixing_ratio',
    'is_third_body',
  ];
  constructor(params) {
    this.name = params['name'];
    this.molecular_weight = params['molecular_weight'];
    this.constant_concentration = params['constant_concentration'];
    this.constant_mixing_ratio = params['constant_mixing_ratio'];
    this.is_third_body = params['is_third_body'];
    this.other_properties = {};
    // Allows end-users to add arbitrary properties as simple key-value pairs just like the other defined properties
    Object.entries(params).forEach(([key, value]) => {
      if (this.#keys.includes(key) == false) {
        this.other_properties[key] = value;
      }
    });
  }
  getJSON() {
    let obj = {};
    obj['name'] = this.name;
    obj['molecular weight [kg mol-1]'] = this.molecular_weight;
    obj['constant concentration [mol m-3]'] = this.constant_concentration;
    obj['constant mixing ratio [mol mol-1]'] = this.constant_mixing_ratio;
    obj['is third body'] = this.is_third_body;
    const ops = convertOtherProperties(this.other_properties);
    Object.assign(obj, ops);
    return obj;
  }
}

class PhaseSpecies {
  #keys = ['name', 'diffusion_coefficient'];
  constructor(params) {
    this.name = params['name'];
    this.diffusion_coefficient = params['diffusion_coefficient'];
    this.other_properties = {};
    Object.entries(params).forEach(([key, value]) => {
      if (this.#keys.includes(key) == false) {
        this.other_properties[key] = value;
      }
    });
  }
  getJSON() {
    let obj = {};
    obj['name'] = this.name;
    obj['diffusion coefficient [m2 s-1]'] = this.diffusion_coefficient;
    const ops = convertOtherProperties(this.other_properties);
    Object.assign(obj, ops);
    return obj;
  }
}

class Phase {
  #keys = ['name', 'species'];
  constructor(params) {
    this.name = params['name'];
    this.species = params['species'];
    this.other_properties = {};
    Object.entries(params).forEach(([key, value]) => {
      if (this.#keys.includes(key) == false) {
        this.other_properties[key] = value;
      }
    });
  }
  getJSON() {
    let obj = {};
    obj['name'] = this.name;
    obj['species'] = this.species.map((s) => {
      if (s instanceof PhaseSpecies) return s.getJSON();
      if (s instanceof Species) {
        const ps = new PhaseSpecies({ name: s.name });
        return ps.getJSON();
      }
    });
    const ops = convertOtherProperties(this.other_properties);
    Object.assign(obj, ops);
    return obj;
  }
}

class ReactionComponent {
  #keys = ['species_name', 'coefficient'];
  constructor(params) {
    this.species_name = params['species_name'];
    this.coefficient = params['coefficient'] || 1.0;
    this.other_properties = {};
    Object.entries(params).forEach(([key, value]) => {
      if (this.#keys.includes(key) == false) {
        this.other_properties[key] = value;
      }
    });
  }
  getJSON() {
    let obj = {};
    obj['species name'] = this.species_name;
    obj['coefficient'] = this.coefficient;
    const ops = convertOtherProperties(this.other_properties);
    Object.assign(obj, ops);
    return obj;
  }
}

export const types = { Species, PhaseSpecies, Phase, ReactionComponent };
