// sounds
class Sounder {
  constructor(args) {
    this.name = args.name;
    this.soundfile = args.soundfile;
    this.gain = args.gain; // (dB)
    this.latitude = args.location[0];
    this.longitude = args.location[1];
    this.spread = args.spread; // (deg)
    this.distmap = args.distmap;
    this.volmin = args.volmin; // (dB)
    this.ramptime = args.ramptime; // (seconds)
    this.zone = 0;
  }

  async load() {
    //start sound playback
    this.pv = new Tone.PanVol(0, -99).toDestination();
    this.snd = await AudioImport(this.soundfile); // NOTE: url with spaces didn't work here.
    this.snd.connect(this.pv);
    this.snd.start();
    this.snd.loop = true;
  }

  update_location() {
    this.ang = getBearing(latitude, longitude, this.latitude, this.longitude); // (deg)
    this.angerr = ((this.ang - heading + 360) % 360 + 180) % 360 - 180;
    this.dist = getDistance(latitude, longitude, this.latitude, this.longitude); // (km)
    //
    this.distvol = map(this.dist, this.distmap[0], this.distmap[1], this.distmap[2], this.distmap[3], true); //(dB)
  }
  update_panvol() {
    // console.log('pv');
    //
    //update sound pan/volume
    //

    // (from Pure Data patch "iamyou", [eqpan2~])
    // arg #1 (inlet #3): width:
    // -width*(1.5) ~ -width/2 -> left fade-in
    // -width/2 ~ width/2 -> cross fading
    // +width/2 ~ width*(1.5) -> right fade-out

    //if close enough. don't do pan/vol, but just playback with full volume.
    this.zone = 0;
    if (this.dist < 0.07) {
      this.zone = 1;
      this.pv.pan.rampTo(0, this.ramptime);
      this.pv.volume.rampTo(this.gain, this.ramptime); //(dB)
      return;
    }

    let panleft_start = this.spread * (-1.5);
    let panleft_end = this.spread * (-0.5);
    let panright_start = this.spread * (0.5);
    let panright_end = this.spread * (1.5);

    //pan & volume
    if (this.angerr > panleft_start && this.angerr < panleft_end) {
      //left fade-in
      this.pv.pan.value = -1; //left-full
      this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panleft_start, panleft_end, this.volmin, 0), this.ramptime); //(dB)
    } else if (this.angerr > panleft_end && this.angerr < panright_start) {
      //cross fading; //(dB)
      this.pv.pan.value = map(this.angerr, panleft_end, panright_start, -1, 1);
      this.pv.volume.rampTo(this.distvol + this.gain, this.ramptime); //(dB)
    } else if (this.angerr > panright_start && this.angerr < panright_end) {
      //right fade-out
      this.pv.pan.value = 1; //right-full
      this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panright_start, panright_end, 0, this.volmin), this.ramptime); //(dB)
    } else {
      //slience
      this.pv.volume.rampTo(-99, 10); //(dB)
    }
  }

  draw() {
    //draw sound location
  }

  static allStart(array) {
    array.forEach(item => {
      if (item.snd.state != 'started') item.snd.start();
    });
  }

  static allStop(array) {
    array.forEach(item => {
      if (item.snd.state != 'stopped') item.snd.stop();
    });
  }

  static allSilent(array) {
    array.forEach(item => {
      item.pv.volume.rampTo(-99, item.ramptime);
    });
  }
}

//
class RadioSounder extends Sounder {

  constructor(args) {
    super(args);
  }

  //do nothing
  async load() {
    ;
  }

  link(audiotag) {
    //start sound playback
    this.pv = new Tone.PanVol(0, -99).toDestination();

    //native webaudio
    this.source = Tone.context.createMediaElementSource(audiotag);
    this.snd = undefined;
    this.gainnode = Tone.context.createGain();
    this.gainnode.gain.value = 1; // 1 == max. volume

    //a hacky native-to-Tonejs connection(?!)
    this.source.connect(this.gainnode).connect(this.pv.input.input);
  }

  update() {
    super.update();

    // console.log('hi!');
  }
}

//p5
class Compass {
  constructor(size, colors) {
    this.size = size;
    this.colors = colors;
    this.pointer = 0;
  }

  draw() {
    push();
    //
    scale(this.size);
    //
    translate(0.5, 0.5);
    //
    noStroke();
    //
    fill(this.colors[0]);
    circle(0, 0, 0.9);
    //
    fill(this.colors[1]);
    rotate(this.pointer);
    quad(0.1, 0.2, 0, -0.4, -0.1, 0.2, 0, 0.1);
    //
    fill(this.colors[2]);
    circle(0, 0, 0.05);
    //
    pop();
  }
}
