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

public class DVBCard extends TVCard
{
  /**
   * @param deviceid
   * @throws Misconfiguration 
   */
  public DVBCard(int deviceid)
    throws Misconfiguration, CantUseTVCard, SQLException
  {
    myID = deviceid;
    readDatabase();
    myDeviceName = "/dev/dvb/adapter" + myDeviceNumber + "/";
    // TODO test if usable
    Util.debug(this.toString());
  }
  protected void readDatabase()
    throws Misconfiguration, SQLException
  {
    PreparedStatement getCard = DB.me.database().prepareStatement("SELECT * FROM device WHERE deviceid = ?");
    getCard.setInt(1, myID);
    ResultSet rs = getCard.executeQuery();
    try {
      if (!rs.first())
    	  throw new Misconfiguration("No such card id");
      myHost = rs.getString("host");
      myIsLocal = Util.isThisHost(myHost);
      myDeviceNumber = rs.getByte("dvb_num");
      myDVBSubType = rs.getString("devicesubtype");
      myFullTS = rs.getBoolean("dvb_fullts");

      // checks
      String deviceType = rs.getString("devicetype"); 
      if (deviceType == null || deviceType.trim().length() == 0)
        deviceType = "(empty)";
      if (myDVBSubType == null || myDVBSubType.trim().length() == 0)
        myDVBSubType = "(empty)";
      if ( ! deviceType.equals("DVB"))
        throw new Misconfiguration("Device type in database is " + deviceType + ", but this is the DVB implementation");
      if ( ! myDVBSubType.equals("DVB-T") &&
          ! myDVBSubType.equals("DVB-C") &&
          ! myDVBSubType.equals("DVB-S") &&
          ! myDVBSubType.equals("DVB-S2"))
        throw new Misconfiguration("Device DVB subtype " + myDVBSubType + " is not supported");
    } catch (Exception e) {
      throw new Misconfiguration("Device ID " + myID + " misconfigured in database", e);
    }
  }
  public TVRecorder newRecording()
    throws Misconfiguration, SQLException
  {
    if (isLocal())
      return new DVBRecorder(this);
    else
      return new RemoteTVRecorder(this);
  }
  public DVBTuner tuner()
    throws Misconfiguration, CantUseTVCard
  {
    if (myTuner == null)
    {
      //myTuner = new DVBTunerShell(this);
      myTuner = new DVBTunerNativeJNILinux(this);
    }

    return myTuner;
  }

  /**
   * For DVBRecorder only.
   * Close (or drop?) the stream after use,
   * otherwise you'll block later recordings.
   * 
   * @return the dvr device, e.g. /dev/dvb/adapter0/dvr0
   * @throws CantUseTVCard
   */
  public InputStream recordDevice()
    throws CantUseTVCard
  {
    String devicename = myDeviceName + "dvr0";
    try {
      return new FileInputStream(devicename);
    } catch (FileNotFoundException e) {
      throw new CantUseTVCard("Could not open DVB card " + devicename, e);
    }
  }
  /**
   * For DVBTunerNative* only.
   * Close the file handle after use,
   * otherwise you'll block later recordings.
   * 
   * @return the control device filename, e.g. "/dev/dvb/adapter0/frontend0"
   */
  String frontendDeviceFilename()
  {
    return myDeviceName + "frontend0";
  }
  /**
   * @return the de-multiplexer device filename, e.g. "/dev/dvb/adapter0/demux0"
   */
  String demuxDeviceFilename()
  {
    return myDeviceName + "demux0";
  }
  /**
   * This card can record that channel
   */
  public boolean canRecord(TVChannel tvchannel)
    throws Misconfiguration
  {
    if ( ! (tvchannel instanceof DVBChannel))
    	throw new Misconfiguration("Using a non-DVB channel on a DVB card");

    // TODO check device_channel mapping in DB, in super()

    if ( ! canRecord(((DVBChannel) tvchannel).transponder()))
      return false;

    return true;
  }
  /**
   * This card can record that DVB transponder
   */
  public boolean canRecord(DVBTransponder transponder)
    throws Misconfiguration
  {
    if (transponder instanceof DVBTTransponder && myDVBSubType.equals("DVB-T"))
      return true;
    if (transponder instanceof DVBCTransponder && myDVBSubType.equals("DVB-C"))
      return true;
    if (transponder instanceof DVBS2Transponder && myDVBSubType.equals("DVB-S2"))
      return true;
    if (transponder instanceof DVBSTransponder &&
       (myDVBSubType.equals("DVB-S2") || myDVBSubType.equals("DVB-S")))
      return true;

    return false;
  }
  public boolean canRecordSimultanously(Collection<? extends TVChannel> channels)
  {
    return false;
/*    // compare transponder of first channel with every other
    DVBChannel first = null;
    for (TVChannel i : channels)
    {
      DVBChannel channel = (DVBChannel) i;
      if (first == null)
      {
        first = channel;
        continue;
      }
      if (!channel.sameTransponder(first))
        return false;
    }
    return true;
*/  }
  public int id() { return myID; }
  /**
   * To display to user (only)
   */
  public String name() { return myDeviceName; }
  public String host() { return myHost; }
  public boolean isLocal() { return myIsLocal; }
  public String toString()
  {
    return "DVB card " + myID + " " + myDeviceName + (myIsLocal ? " (" : " (not ") + "local)";
  }

  // Data
  protected int myID;
  protected byte myDeviceNumber;
  protected String myDeviceName; 
  protected String myDVBSubType; 
  protected boolean myFullTS;
  protected String myHost;
  protected boolean myIsLocal;
  protected DVBTuner myTuner = null;
}
