package org.bucksch.zeipis.recorder;
import org.bucksch.zeipis.all.*;
import java.util.*;
import java.sql.*;

public class DVBChannel extends TVChannel
{
  public DVBChannel(int channelid)
    throws Misconfiguration, SQLException
  {
    myChannelID = channelid;
    readFromDatabase();
  }
  /**
   * Creates an un-inited object.
   * Needed by channel importers to create a channel from data other than the DB.
   * You need to populate it ASAP, or not use it as valid channel object,
   * because it violates the assumptions for it.
   *
   * DO NOT use such an object for tuning or anything else in the core app!
   * It's only a placeholder object, from DVBScan to ChannelsToDBImporter or similar. 
   */
  public DVBChannel()
  {
    myChannelID = -1;
    myStationLongName = null;
    myStationShortName = null;
    myTransponder = null;
  }
  /**
   * Creates an un-inited object.
   * @see DVBChannel()
   */
  public DVBChannel(DVBTransponder t)
  {
    myChannelID = -1;
    myStationLongName = null;
    myStationShortName = null;
    myTransponder = t;
  }
  protected void readFromDatabase()
    throws Misconfiguration, SQLException
  {
    ResultSet rs;
    try {
      rs = DB.me.database().createStatement().executeQuery("SELECT * FROM channel LEFT JOIN station ON (channel.stationid = station.stationid) WHERE channelid = " + myChannelID);
      if ( ! rs.first())
        throw new NoSuchFieldException();
    } catch (Exception e) {
      throw new IllegalStateException("Channel ID " + myChannelID + " not found in database", e);
    }
    try {
      readFromDatabaseResultSet(rs);
    } catch (SQLException e) {
      throw new Misconfiguration("Channel ID " + myChannelID + " is misconfigured in database", e); // XXX tell the exact field which is wrong
    }    
  }
  protected void readFromDatabaseResultSet(ResultSet rs)
    throws Misconfiguration, SQLException
  {    
    int transponderid = rs.getInt("dvb_transponderid");
    myTransponder = CoreData.me.myDVBTransponders.get(transponderid);
    if (myTransponder == null)
      throw new Misconfiguration("DVB transponder ID " + transponderid + " not found in DB table dvb_transponder (or CoreData.myDVBTransponders)");
    /* I'm assuming that CoreData.me.myDVBTransponders gets populated before.
     * Alternatively, we could create the DVBransponder here and add it to CoreData. */
    assert( ! CoreData.me.myDVBTransponders.isEmpty()); // CoreData.myDVBTransponders should be populated before creating DVBChannel

    myStationID = rs.getInt("stationid");
    myStationLongName = rs.getString("long_name");
    myStationShortName = rs.getString("short_name");
    serviceID = rs.getInt("dvb_serviceid");

    String langs = rs.getString("languages");
    if (langs != null && langs.length() > 0)
      languages.addAll(Arrays.asList(langs.split(",")));

    encrypted = rs.getBoolean("dvb_encrypted");
    String encryptSystemsStr = rs.getString("dvb_encrypt_systems");
    if (encryptSystemsStr != null && encryptSystemsStr.length() > 0)
    {
      for (String str : encryptSystemsStr.split(","))
      {
        if (str.startsWith("0x") && str.length() > 2)
          encryptSystems.add(Integer.parseInt(str.substring(2), 16));
        if (str.length() > 0)
          encryptSystems.add(Integer.parseInt(str.substring(2)));
      }
    }
  }

  /**
   * PIDs can come from 3 sources: channel table, pidcache table, and from stream
   * TODO get from stream
   */
  void getPIDsFromDB()
    throws Misconfiguration, SQLException
  {
    ResultSet rs;
    try {
      /*
      // dvb_pid_vid, dvb_pid_aud FROM channel
      // TODO PreparedStatement
      rs = DB.me.database().createStatement().executeQuery("SELECT dvb_pid_vid, dvb_pid_aud FROM channel WHERE channelid = " + myChannelID);
      if (!rs.first())
        throw new Misconfiguration("Can't find channel " + myChannelID + " in database");
      pids.add(rs.getInt(1));
      pids.add(rs.getInt(2));
      */
      // pidcache
      rs = DB.me.database().createStatement().executeQuery("SELECT pid FROM pidcache WHERE channelid = " + myChannelID);
      while (rs.next())
        pids.add(rs.getInt(1));
      // check
      if (pids.size() == 0)
        throw new NoSuchFieldException();
    } catch (Exception e) {
      throw new Misconfiguration("PIDs for channel ID " + myChannelID + " not found in database", e);
    }
  }

  public DVBTransponder transponder()
  {
    return myTransponder;
  }
  public boolean sameTransponder(DVBChannel other, boolean strict)
  {
    return myTransponder.sameTransponder(other.transponder(), strict);
  }

  public String toString()
  {
    return "DVB channelid " + myChannelID + " " + myStationLongName;
  }

  // Data
  protected DVBTransponder myTransponder;
  public int serviceID;
  public int pmtPID = -1;
  public Set<Integer> pids = Util.newSet();

  // only for importer
  public String dvbServiceName = "";
  public String dvbProviderName = "";
  public enum ChannelContentType { TV, Radio, Data, Other };
  public ChannelContentType contentType = ChannelContentType.TV;
  public boolean isHDTV = false;
  public Set<String> languages = Util.newSet(); // ISO 639-1 2-letter language codes, e.g. "en", "de", "es"
  public boolean encrypted = false;
  public Set<Integer> encryptSystems = Util.newSet(); // System IDs of CA systems which can decrypt this channel. A CAM supports one or more CA systems.
  public boolean commercialFree = false;
  public String xmltvid = null;
}
