package org.bucksch.zeipis.importer;
import org.bucksch.zeipis.all.Util;
import org.bucksch.zeipis.recorder.*;
import java.io.*;
import java.util.Locale;

public class ChannelsConfImporter
{
  /**
   * @param card   Only needed to associate the channel with the device
   * @param file  The channels.conf file. A stream, because it may be the stdout from scan, unzip etc..
   * @param formatStr   There are many different channel.conf file formats, plus scan initial tuning files.
   *      This tells which one this is. For possible values, see Importer.usage() or impl here.
   * @param updateonly   Don't add new channels
   * @param addonly   Don't change existing channels
   */
	public ChannelsConfImporter(DVBCard card, InputStream file, String formatStr, boolean updateonly, boolean addonly)
    throws Exception
	{  
    int format;
    if (formatStr.equals("init")) format = 1;
    else if (formatStr.equals("szap")) format = 2;
    else if (formatStr.equals("tzap")) format = 3;
    else if (formatStr.equals("czap")) format = 4;
    else throw new Exception("Format " + formatStr + " unknown");

	  ChannelsToDBImporter dbImporter = new ChannelsToDBImporter(card, updateonly, addonly);
    BufferedReader br = new BufferedReader(new InputStreamReader(file));
    
    String input;
    while ((input = br.readLine()) != null)
    {
      try {
        if (input.trim().length() == 0 ||
           input.charAt(0) == '#')
          continue;
        Util.debug("Processing line " + input);
  
        DVBChannel c;
        if (format == 1) c = parseScanInitChannel(input);
        else if (format == 2) c = parseZapSChannel(input);
        else if (format == 3) c = parseZapTChannel(input);
        else if (format == 4) c = parseZapCChannel(input);
        else throw new Exception("Format " + format + " unknown");
  
        DVBScan.Transponder transponder = new DVBScan.Transponder();
        transponder.tuning = c.transponder();
        if (format != 1)
          transponder.channels.add(c);
        dbImporter.importTransponder(transponder);
      } catch (Exception e) { Util.error(e); }
    }
	}

  public DVBChannel parseZapSChannel(String line)
    throws Exception
  {
    // LibertyTV FR:12551:v:0:22000:941:943:12120

    DVBSTransponder t = new DVBSTransponder();
    DVBChannel c = new DVBChannel(t);
    String[] fields = line.split(":");

    c.dvbServiceName = fields[0];
    t.frequency = Integer.valueOf(fields[1]) * 1000;
    t.polarity = fields[2].toUpperCase(Locale.ENGLISH).charAt(0);
    //int satNo = Integer.valueOf(fields[3]);
    t.symbolrate = Integer.valueOf(fields[4]) * 1000;
    c.pids.add(Integer.valueOf(fields[5]));
    c.pids.add(Integer.valueOf(fields[6]));
    c.serviceID = Integer.valueOf(fields[7]);

    return c;
  }
  public DVBChannel parseZapTChannel(String line)
    throws Exception
  {
    // ZDF info:482000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:545:546:514

    DVBTTransponder t = new DVBTTransponder();
    DVBChannel c = new DVBChannel(t);
    String[] fields = line.split(":");

    c.dvbServiceName = fields[0];
    t.frequency = Integer.valueOf(fields[1]);
    t.inversion = parseOnOff(fields[2].replace("INVERSION_", ""));
    t.bandwidth = fields[3].replace("BANDWIDTH_", "").replace("_MHZ", "").charAt(0);
    t.hp_code_rate = fields[4].replace("FEC_", "").replace("_", "/");
    t.lp_code_rate = fields[5].replace("FEC_", "").replace("_", "/");
    t.modulation = fields[6].replace("_", "");
    t.transmission_mode = fields[7].replace("TRANSMISSION_MODE_", "").charAt(0);
    t.guard_interval = fields[8].replace("GUARD_INTERVAL_", "").replace("_", "/");
    t.hierarchy = parseOnOff(fields[9].replace("HIERARCHY_", ""));
    c.pids.add(Integer.valueOf(fields[5]));
    c.pids.add(Integer.valueOf(fields[6]));
    c.serviceID = Integer.valueOf(fields[7]);

    return c;
  }
  public DVBChannel parseZapCChannel(String line)
    throws Exception
  {
    // RTL Television:346000000:INVERSION_AUTO:6900000:FEC_NONE:QAM_64:163:104:12003

    DVBCTransponder t = new DVBCTransponder();
    DVBChannel c = new DVBChannel(t);
    String[] fields = line.split(":");

    c.dvbServiceName = fields[0];
    t.frequency = Integer.valueOf(fields[1]);
    t.symbolrate = Integer.valueOf(fields[3]);
    // inversion: Not implemented for DVB-C/S, always AUTO
    t.fec = fields[4].replace("FEC_", "");
    t.modulation = fields[5].replace("_", "");
    c.pids.add(Integer.valueOf(fields[6]));
    c.pids.add(Integer.valueOf(fields[7]));
    c.serviceID = Integer.valueOf(fields[8]);

    return c;
  }

  public DVBChannel parseScanInitChannel(String line)
    throws Exception
  {
    String[] fields = line.split(" +");
    for (String field : fields)
      Util.debug("field: " + field);

    char type = fields[0].charAt(0);
    if (type == 'S') return parseScanInitSChannel(fields);
    else if (type == 'T') return parseScanInitTChannel(fields);
    else if (type == 'C') return parseScanInitCChannel(fields);
    else throw new Exception("Scan init prefix " + type + " unknown");
  }

  public DVBChannel parseScanInitSChannel(String[] fields)
    throws Exception
  {
    // # freq pol sr fec
    // S 12551500 V 22000000 5/6

    DVBSTransponder t = new DVBSTransponder();
    DVBChannel c = new DVBChannel(t);
    c.dvbServiceName = fields[0];
    t.frequency = Integer.valueOf(fields[1]);
    t.polarity = fields[2].toUpperCase(Locale.ENGLISH).charAt(0);
    t.symbolrate = Integer.valueOf(fields[4]);
    t.fec = fields[4];
    return c;
  }

  public DVBChannel parseScanInitTChannel(String[] fields)
    throws Exception
  {
    // #T  freq    bw   coderate_HP coderate_LP modulation transmode guard-int hierarchy
    // # Kanal 8, ARD Multiplex 1, Grosser Feldberg 10kW, Hohe Wurzel 20kW, FFM-Turm 10kW
    // T 198500000 7MHz 2/3         NONE        QAM16      8k        1/4       NONE

    DVBTTransponder t = new DVBTTransponder();
    DVBChannel c = new DVBChannel(t);
    t.frequency = Integer.valueOf(fields[1]);
    t.bandwidth = fields[2].charAt(0);
    t.hp_code_rate = fields[3];
    t.lp_code_rate = fields[4];
    t.modulation = fields[5];
    t.transmission_mode = fields[6].charAt(0);
    t.guard_interval = fields[7];
    t.hierarchy = parseOnOff(fields[8]);
    t.inversion = 'a';
    return c;
  }

  public DVBChannel parseScanInitCChannel(String[] fields)
    throws Exception
  {
    // # freq sr fec mod
    // C 113000000 6900000 NONE QAM64

    DVBCTransponder t = new DVBCTransponder();
    DVBChannel c = new DVBChannel(t);
    c.dvbServiceName = fields[0];
    t.frequency = Integer.valueOf(fields[1]);
    t.symbolrate = Integer.valueOf(fields[2]);
    t.fec = fields[3];
    t.modulation = fields[4];
    return c;
  }

  protected char parseOnOff(String field)
    throws Exception
  {
    if (field.equals("NONE")) return 'N';
    if (field.equals("ON")) return '1';
    if (field.equals("OFF")) return '0';
    if (field.equals("AUTO")) return 'A';
    throw new Exception("Unknown value, expected ON/OFF/AUTO/NONE");
  }
}
