package zap;

import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Vstup extends Thread{
    public BufferedReader ds;
    public PipedOutputStream o;
    
    public Vstup(String suborIn) throws FileNotFoundException {
        ds = new BufferedReader(new FileReader(suborIn));
        o = new PipedOutputStream();
    }

    @Override
    public void run(){
        int znak;

        try {
            while ((znak = ds.read()) != -1) {
                o.write(znak);
            }
            o.close();
            ds.close();
        } catch (IOException ex) {
            Logger.getLogger(Vstup.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}


public class Vystup extends Thread {
    public BufferedWriter ds;
    public PipedInputStream i;
    //public PipedInputStream o;

    public Vystup(String suborIn) throws FileNotFoundException, IOException {

        ds = new BufferedWriter(new FileWriter(suborIn));

        i = new PipedInputStream();
        
    }

    @Override
    public void run(){
        int znak;
        try {
            while ((znak = i.read()) != -1) {
                ds.write(znak);
                System.out.println((char)znak);
            }
            i.close();
        } catch (Exception ex) {
            Logger.getLogger(Vstup.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                ds.close();
            } catch (IOException ex) {
                Logger.getLogger(Vystup.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}


public class Hrana {
    public char stav1;
    public char stav2;
    public int druh;
    public char p;
    public Hrana(char s1, char s2, char d, char pIn) {
        stav1=s1;
        stav2=s2;
        if (d=='?') druh=1;
        if (d=='!') druh=2;
        p=pIn;
    }
    public void Vypis() {
        System.out.print(stav1 + "-" + stav2 + druh + p);
    }
}


public class LTS extends Thread {
    public char stav = '0';
    public PipedInputStream i;
    public PipedOutputStream o;

    public List<Hrana> h = new LinkedList<Hrana>();

    public LTS() {
        i = new PipedInputStream();
        o = new PipedOutputStream();
    }

    @Override
    public void run(){
        int znak;
        try {
            znak = i.read();
            if (znak != -1) {
                while(true) {
                    boolean pouzite = false;
                    for(int j=0; j<h.size(); j++) {
                        if(h.get(j).stav1 == stav) {
                            if (h.get(j).druh == 1 && (h.get(j).p == (char)znak)) {
                                stav = h.get(j).stav2;
                                znak = i.read();
                                if (znak==-1) break;
                                pouzite = true;
                            }
                        }
                    }
                    for (int j=0; j<h.size(); j++) {
                        if(h.get(j).stav1 == stav) {
                           if (h.get(j).druh == 2) {
                                stav = h.get(j).stav2;
                                o.write(h.get(j).p);
                                pouzite = true;
                            }
                        }
                    }
                    if (!pouzite) {
                        for(int j=0; j<h.size(); j++) {
                        if(h.get(j).stav1 == stav) {
                            if (h.get(j).druh == 1 && (h.get(j).p == (char)('*'))) {
                                stav = h.get(j).stav2;
                                znak = i.read();
                                if (znak==-1) break;
                                pouzite = true;
                            }
                        }
                    }
                    }
                    if (!pouzite) {
                        o.write(znak);
                        znak = i.read();
                    }
                    if (znak==-1) break;
                }
                o.write(znak);
            }
            o.close();
            i.close();

        } catch (IOException ex) {
            Logger.getLogger(Vstup.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


public class Main {

    //public static String vstup;

   public static List<LTS> list;

   public static void nacitajLTS(String suborIn) throws FileNotFoundException, IOException {
       BufferedReader ds = new BufferedReader(new FileReader(suborIn));
       String line;
       list = new LinkedList<LTS>();
        boolean novy = true;
        while ((line = ds.readLine()) != null) {
            if (novy) {
                list.add(new LTS());
            }
            if (line.length() < 1) {
                novy = true;
            } else {
                list.get(list.size()-1).h.add(new Hrana(line.charAt(0), line.charAt(2), line.charAt(4),line.charAt(5)));
                novy=false;
            }
        }
   }

    public static void main(String[] args) throws FileNotFoundException, IOException {

        if (args.length == 3) {
            nacitajLTS(args[0]);
            Vstup vstup = new Vstup(args[1]);
            Vystup vystup = new Vystup(args[2]);
            vstup.o.connect(list.get(0).i);
//            for (int k=list.size()-2; k==0; k--){
//                list.get(k).o.connect(list.get(k+1).i);
//            }
           list.get(4).o.connect(vystup.i);
            list.get(3).o.connect(list.get(4).i);
            list.get(2).o.connect(list.get(3).i);
          list.get(1).o.connect(list.get(2).i);
           list.get(0).o.connect(list.get(1).i);
            //list.get(1).i.connect(vstup.o);

            //list.get(list.size()-1).o.connect(vystup.i);
            vystup.start();
//            for (int k=list.size()-5; k==0; k--){
//                list.get(k).start();
//            }

            list.get(4).start();
            list.get(3).start();
            list.get(2).start();
            list.get(1).start();
            list.get(0).start();

            vstup.start();

        }
        // TODO code application logic here
    }
}