/*
 * jTsSplitter - java based mpeg2ts splitter.
 * Copyright (C) 2009-2012 Yukikaze
 */

package jtssplitter;
import java.util.ArrayList;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Arrays;
import jtssplitter.data.PATData;
import jtssplitter.data.PIDs;
import jtssplitter.data.PMTData;
/**
 *
 * @author Administrator
 */
public class Tsfile {
    public void splitTS_byte(String origpath,String destpath,int csch){
        int[] pids=null;
        int p_table=0;
        if (csch>0){
            p_table=csch;
        }else{
            p_table=getFirstP_Table_byte(origpath);
        }
        PIDs pidss=getTablePID_byte(origpath,p_table);
        p_table=pidss.Program_Table;
        pids=pidss.PIDs;
        int pmt_pid=pidss.PMT_PID;
        System.out.println("番組の同定終了");
        System.out.println("Program Table : "+Integer.toString(p_table));
        byte[] tb=new byte[188];
        try {
            FileInputStream in = new FileInputStream(origpath);
            FileOutputStream fos=new FileOutputStream(destpath);
            BufferedInputStream bis=new BufferedInputStream(in,128*188);
            BufferedOutputStream bos=new BufferedOutputStream(fos);
            byte[] wbyte=null;
            boolean end=false;
            int ik=0;
            boolean readend=false;
            Mpeg2TSPacket m2tpp;
            m2tpp=new Mpeg2TSPacket();
            while (readend==false){
                byte[] tstt=new byte[3];
                bis.mark(188*2);
                bis.read(tstt);
                bis.reset();
                wbyte=null;
                Mpeg2TSPacket m2tp;
                m2tp=new Mpeg2TSPacket();
                //int ii=m2tpp.getPIDFirst(tstt);
                int ii=m2tpp.getPIDFirst_byte(tstt);
                //if (ii!=i2){
                //    System.out.println("not match");
                //}
                boolean alreadyreaded=false;
                for (int k=0;k<pids.length;k++){
                    if (alreadyreaded==false){
                        if (ii==pids[k]){
                            alreadyreaded=true;
                            int readti=bis.read(tb);
                            if ((ii==0)&&(readti>187)){
                                Mpeg2TSPacket m2tp2=new Mpeg2TSPacket();
                                m2tp2.readTS_byte(tb);
                                ArrayList<PATData> pats=new ArrayList<PATData>();
                                pats=m2tp2.getPAT();
                                boolean containp_table=false;
                                for (int iii=0;iii<pats.size();iii++){
                                    if (pats.get(iii).Program_TABLE==p_table){
                                        containp_table=true;
                                    }else if (csch > 0){
                                        containp_table=true;
                                    }
                                }
                                if (!containp_table){
                                    for (int iii=0;iii<pats.size();iii++){
                                        if (pats.get(iii).Program_TABLE>0){
                                            System.out.println("Program Tableの変更を検知"+Integer.toString(p_table)+" to "+Integer.toString(pats.get(iii).Program_TABLE));
                                            p_table=pats.get(iii).Program_TABLE;
                                            for (int it=0;it<pids.length;it++){
                                                if (pids[it]==pmt_pid){
                                                    pmt_pid=pats.get(iii).PID;
                                                    pids[it]=pmt_pid;
                                                }
                                            }
                                            iii=pats.size();
                                        }
                                    }
                                }

                                wbyte=m2tpp.splitPAT_byte(tb,p_table);
                                //wbyte=m2tpp.splitPAT(tb, p_table);
                                /*byte[] wbytet=m2tpp.splitPAT(tb, p_table);
                                for (int kk=0;kk<wbyte.length;kk++){
                                    if (wbyte[kk]==wbytet[kk]){
                                        //System.out.println(":match");
                                    }else{
                                        System.out.print(kk);
                                        System.out.println(":not match");
                                    }
                                }*/
                                //wbyte=wbytet;*/
                            }else if ((ii==pmt_pid)&&(readti>187)){
                                wbyte=tb;
                                ArrayList<PMTData> pmtss;
                                try{
                                    pmtss=m2tpp.readPMTglobal_byte(tb, pmt_pid);
                                }catch(NullPointerException e){
                                    pmtss=new ArrayList<PMTData>();
                                }
                                if (pmtss.size()>0){
                                    int[] new_pids=new int[pmtss.size()+3];
                                    new_pids[pmtss.size()]=0;
                                    new_pids[pmtss.size()+1]=pmt_pid;
                                    new_pids[pmtss.size()+2]=pmtss.get(0).PCR_PID;
                                    for (int i=0;i<pmtss.size();i++){
                                        new_pids[i]=pmtss.get(i).Elementary_PID;
                                    }
                                    if (!Arrays.equals(pids, new_pids)){
                                        pids=new_pids;
                                    }
                                }

                            /*}else if ((ii==0x0012)&&(readti>187)){
                                ArrayList<EITData> eitss=m2tpp.readEIT(tb);
                             */
                            }else if (readti>187){
                                wbyte=tb;

                            }else {
                                readend=true;
                            }
                            k=pids.length;
                        }
                    }
                ik++;
            }
            if (alreadyreaded==false){
                bis.skip(188);
            }
                if (wbyte!=null){
                    bos.write(wbyte);
                }
            }
            bis.close();
            bos.flush();
            bos.close();
            in.close();
            fos.close();

        } catch (IOException ex) {
            Logger.getLogger(Tsfile.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    private PIDs getTablePID_byte(String fpath,int p_table){
        /**
         * PIDを取得し、これと思われる必要なPIDを抜き出す。
         * @return プログラム番号(return[0])とPIDのリスト(return[1-])
         */
        FileInputStream in = null;
        PIDs pids=new PIDs();
        int[] reti=null;
        try {
            ArrayList<Integer> ret=new ArrayList<Integer>();
            byte[] tb = new byte[188];
            int[] ib = new int[188];
            ArrayList<PATData> pat = new ArrayList<PATData>();
            ArrayList<PMTData> pmt = new ArrayList<PMTData>();
            String[] sb = new String[188];
            in = new FileInputStream(fpath);
            int imax=1000;
            for (int i = 0; i < imax ; i++) {
                if (in.read(tb)==-1){
                    in.close();
                    System.out.println("Program Table and PMT not found.");
                    System.exit(1);
                }
                String last8;
                Mpeg2TSPacket m2tp;
                m2tp = new Mpeg2TSPacket();
                m2tp.setPAT(pat);
                m2tp.setPMT(pmt);
                m2tp.readTS_byte(tb);
                pat = m2tp.getPAT();
                for (int i2=0;i2<pat.size();i2++){
                    PATData patdd=pat.get(i2);
                    if (pat.get(i2).Program_TABLE==p_table){
                        pat.clear();
                        pat.add(patdd);
                        m2tp.setPAT(pat);
                    }
                }
                ArrayList<PMTData> pmtt=m2tp.getPMT();
                for (int i2=0;i2<pmtt.size();i2++){
                    if (!(pmt.contains(pmtt.get(i2)))){
                        pmt.add(pmtt.get(i2));
                    }
                }
                if ((i==imax-1)&&(pmt.size()==0)){
                    imax=imax+500;
                }
                for (int i2=0;i2<pmt.size();i2++){
                    int itt=ret.size();
                    if (p_table==pmt.get(i2).Program_Table){
                        if (!(ret.contains(pmt.get(i2).Elementary_PID))){
                            ret.add(pmt.get(i2).Elementary_PID);
                            i=imax;
                        }
                    }
                    if (ret.size()==itt){
                        imax=imax+100;
                    }
                }
            }
            PATData patd_det=new PATData();
            for (int i=0;i<pat.size();i++){
                if (pat.get(i).Program_TABLE==p_table){
                    patd_det=pat.get(i);
                    i=pat.size();
                }
            }
            ret.add(0);
            ret.add(patd_det.PID);
            ret.add(pmt.get(0).Elementary_PID);
            for (int i=0;i<pmt.size();i++){
                if (patd_det.Program_TABLE==pmt.get(i).Program_Table){
                    if (!(ret.contains(pmt.get(i).Elementary_PID))){
                        if ((pmt.get(i).Stream_Type==0x02)||(pmt.get(i).Stream_Type==0x0f)){
                            ret.add(pmt.get(i).Elementary_PID);
                        }
                    }
                }
            }
            pids.PMT_PID=patd_det.PID;
            pids.Program_Table=patd_det.Program_TABLE;
            pids.PIDs=new int[ret.size()];
            for (int i=0;i<ret.size();i++){
                pids.PIDs[i]=ret.get(i);
            }
            in.close();
        } catch (IOException ex) {
            Logger.getLogger(Tsfile.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(Tsfile.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return pids;
    }
    public Integer[] getProgramNum_byte(String fpath){
            /**
             * PIDを取得し、これと思われる必要なPIDを抜き出す。
             * @return プログラム番号(return[0])とPIDのリスト(return[1-])
             */
            FileInputStream in = null;
            ArrayList<Integer> retti = new ArrayList<Integer>();
            byte[] tb = new byte[188];
            ArrayList<PATData> pat = new ArrayList<PATData>();
            ArrayList<PATData> pat_ok = new ArrayList<PATData>();
            ArrayList<PMTData> pmt = new ArrayList<PMTData>();
            try {
            in = new FileInputStream(fpath);
            int imax = 7000;
            int mmax = 20000;
            for (int i = 0; i < imax; i++) {
                if (in.read(tb) == -1) {
                    in.close();
                    System.out.println("Program Table not found.");
                    System.exit(1);
                }
                String last8;
                Mpeg2TSPacket m2tp;
                m2tp = new Mpeg2TSPacket();
                m2tp.setPAT(pat);
                m2tp.setPMT(pmt);
                m2tp.readTS_byte(tb);
                pat = m2tp.getPAT();
                pmt = m2tp.getPMT();
                ArrayList<PMTData> pmtt=m2tp.getPMT();
                for (int i2=0;i2<pmtt.size();i2++){
                    if (!(pmt.contains(pmtt.get(i2)))){
                        pmt.add(pmtt.get(i2));
                    }
                }

                if (i>imax-10 && pat_ok.size()==0 && i<mmax){
                    imax=imax+100;
                }
                for (int i3=0;i3<pmt.size();i3++){
                    if (pmt.get(i3).Stream_Type==0x02){
                        for (int i4=0;i4<pat.size();i4++){
                            if (pmt.get(i3).Program_Table==pat.get(i4).Program_TABLE && !(pat_ok.contains(pat.get(i4)))){
                                pat_ok.add(pat.get(i4));
                            }
                        }
                    }
                }
            }
            for (int i5 = 0; i5 < pat_ok.size(); i5++) {
                PATData patdd = pat_ok.get(i5);
                if ((patdd.Program_TABLE != 0) &&(!(retti.contains(patdd.Program_TABLE)))){
                    retti.add(patdd.Program_TABLE);
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(Tsfile.class.getName()).log(Level.SEVERE, null, ex);
        }
        Integer[] rt=retti.toArray(new Integer[retti.size()]);
        return rt;
    }
    private int getFirstP_Table_byte(String fpath){
        /**
         * PIDを取得し、これと思われる必要なPIDを抜き出す。
         * @return プログラム番号(return[0])とPIDのリスト(return[1-])
         */
        FileInputStream in = null;
        int[] reti=null;
        int[] pat_det=new int[2];
        //pat_det[0]=0;
        PATData patdd=new PATData();
        patdd.PID=0;
        try {
            ArrayList ret=new ArrayList();
            byte[] tb = new byte[188];
            int[] ib = new int[188];
            ArrayList<PATData> pat = new ArrayList<PATData>();
            ArrayList<PMTData> pmt = new ArrayList<PMTData>();
            String[] sb = new String[188];
            in = new FileInputStream(fpath);
            //int[] PIDCount = new int[8200];
            int imax=1000;
            calc cal=new calc();
            for (int i = 0; i < imax ; i++) {
                in.read(tb);
                String last8;
                Mpeg2TSPacket m2tp;
                m2tp = new Mpeg2TSPacket();
                m2tp.setPAT(pat);
                m2tp.setPMT(pmt);
                m2tp.readTS_byte(tb);
                pat = m2tp.getPAT();
                pmt = m2tp.getPMT();
                if ((i==imax-1)&&(pmt.size()==0)){
                    imax=imax+500;
                }
            }

            for (int i=0;i<pat.size();i++){
                if (pat.get(i).Program_TABLE>0){
                    patdd=pat.get(i);
                    i=pat.size();
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(Tsfile.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(Tsfile.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return patdd.Program_TABLE;
    }
}