package se.unlogic.eagledns.zoneproviders.db.beans;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xbill.DNS.DClass;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRset;
import org.xbill.DNS.Record;
import org.xbill.DNS.SOARecord;
import org.xbill.DNS.Type;
import org.xbill.DNS.Zone;
import se.unlogic.standardutils.dao.annotations.DAOManaged;
import se.unlogic.standardutils.dao.annotations.Key;
import se.unlogic.standardutils.dao.annotations.OneToMany;
import se.unlogic.standardutils.dao.annotations.Table;
import se.unlogic.standardutils.xml.Elementable;
import se.unlogic.standardutils.xml.XMLElement;
import se.unlogic.standardutils.xml.XMLGenerator;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@XMLElement
@Table(name="zones")
public class DBZone implements Elementable{

   @DAOManaged(autoGenerated=true)
   @Key
   @XMLElement
   private Integer zoneID;

   @DAOManaged
   @XMLElement
   private String name;

   @DAOManaged
   @XMLElement
   private String dclass;

   @DAOManaged
   @XMLElement
   private Long ttl;

   @DAOManaged
   @XMLElement
   private String primaryDNS;

   @DAOManaged
   @XMLElement
   private String adminEmail;

   @DAOManaged
   @XMLElement
   private Long serial;

   @DAOManaged
   @XMLElement
   private Long refresh;

   @DAOManaged
   @XMLElement
   private Long retry;

   @DAOManaged
   @XMLElement
   private Long expire;

   @DAOManaged
   @XMLElement
   private Long minimum;

   @DAOManaged
   @OneToMany
   @XMLElement
   private List<DBRecord> records;

   @DAOManaged
   @XMLElement
   private boolean secondary;

   @DAOManaged
   @XMLElement
   private Timestamp downloaded;

   public DBZone() {

      super();
   }

   public DBZone(Zone zone, boolean secondary) {

      this.parse(zone, secondary);
   }

   public void parse(Zone zone, boolean secondary) {

      if(zone == null){

         this.ttl = null;
         this.adminEmail = null;
         this.serial = null;
         this.refresh = null;
         this.retry = null;
         this.expire = null;
         this.minimum = null;
         this.records = null;
         this.downloaded = null;

      }else{

         SOARecord soaRecord = zone.getSOA();

         this.name = soaRecord.getName().toString();
         this.dclass = DClass.string(soaRecord.getDClass());
         this.ttl = soaRecord.getTTL();
         this.primaryDNS = soaRecord.getHost().toString();
         this.adminEmail = soaRecord.getAdmin().toString();
         this.serial = soaRecord.getSerial();
         this.refresh = soaRecord.getRefresh();
         this.retry = soaRecord.getRetry();
         this.expire = soaRecord.getExpire();
         this.minimum = soaRecord.getMinimum();
         this.secondary = secondary;

         if(secondary){
            this.downloaded = new java.sql.Timestamp(System.currentTimeMillis());
         }

         this.records = new ArrayList<DBRecord>();

         Iterator<?> iterator = zone.iterator();

         while(iterator.hasNext()){

            RRset rRset = (RRset) iterator.next();

            Iterator<?> rrSetIterator = rRset.rrs();

            while(rrSetIterator.hasNext()){

               Record record = (Record) rrSetIterator.next();

               if(record.getType() == Type.SOA){
                  continue;
               }

               this.records.add(new DBRecord(record, zone.getSOA().getName(), this.ttl));
            }
         }
      }
   }

   public String getName() {

      return name;
   }


   public void setName(String name) {

      this.name = name;
   }


   public String getDclass() {

      return dclass;
   }


   public void setDclass(String dclass) {

      this.dclass = dclass;
   }


   public Long getTtl() {

      return ttl;
   }


   public void setTtl(Long ttl) {

      this.ttl = ttl;
   }


   public String getPrimaryDNS() {

      return primaryDNS;
   }


   public void setPrimaryDNS(String primaryDns) {

      this.primaryDNS = primaryDns;
   }


   public String getAdminEmail() {

      return adminEmail;
   }


   public void setAdminEmail(String adminEmail) {

      this.adminEmail = adminEmail;
   }


   public Long getSerial() {

      return serial;
   }


   public void setSerial(Long serial) {

      this.serial = serial;
   }


   public Long getRefresh() {

      return refresh;
   }


   public void setRefresh(Long refresh) {

      this.refresh = refresh;
   }


   public Long getRetry() {

      return retry;
   }


   public void setRetry(Long retry) {

      this.retry = retry;
   }


   public Long getExpire() {

      return expire;
   }


   public void setExpire(Long expire) {

      this.expire = expire;
   }


   public Long getMinimum() {

      return minimum;
   }


   public void setMinimum(Long minimum) {

      this.minimum = minimum;
   }

   public List<DBRecord> getRecords() {

      return records;
   }


   public void setRecords(List<DBRecord> records) {

      this.records = records;
   }


   public Integer getZoneID() {

      return zoneID;
   }


   public void setZoneID(Integer zoneID) {

      this.zoneID = zoneID;
   }

   public Element toXML(Document doc) {

      return XMLGenerator.toXML(this, doc);
   }

   public Zone toZone() throws IOException{

      Name zoneName = Name.fromString(name);
      Name primaryNS = Name.fromString(this.primaryDNS);

      SOARecord soaRecord = new SOARecord(zoneName, DClass.value(dclass), ttl, primaryNS, Name.fromString(this.adminEmail), serial, refresh, retry, expire, minimum);

      //Record primaryNSRecord = Record.newRecord(primaryNS, Type.NS, DClass.value(dclass), ttl);

      int recordCount;

      if(this.records != null){

         recordCount = 1 + this.records.size();

      }else{

         recordCount = 1;
      }

      Record[] recordArray = new Record[recordCount];

      recordArray[0] = soaRecord;
      //recordArray[1] = primaryNSRecord;

      if(records != null){

         int pos = 1;

         for(DBRecord record : this.records){

            recordArray[pos] = record.getRecord(ttl,zoneName);

            pos++;
         }
      }

      return new Zone(zoneName,recordArray);
   }


   public boolean isSecondary() {

      return secondary;
   }


   public void setSecondary(boolean secondary) {

      this.secondary = secondary;
   }

   @Override
   public String toString() {

      return name + " (ID: " + zoneID + ")";
   }


   public Timestamp getDownloaded() {

      return downloaded;
   }


   public void setDownloaded(Timestamp zoneDownloaded) {

      this.downloaded = zoneDownloaded;
   }
}
