import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.io.*; import java.util.Iterator; import java.util.Scanner; import java.util.concurrent.*; import java.util.concurrent.locks.*; // Av/paa-knapper // (de to knappene Kun all-incl og Kun fly som kan slaas paa og av) class AvPaa extends JButton { boolean paa; String tekst; AvPaa (String t, boolean init) { tekst = t; settAvPaa(init); } void settAvPaa (boolean b) { paa = b; if (b) setText(tekst + "ja"); else setText(tekst + "nei"); } void snu () { settAvPaa(! paa); } } class Reisebyra { static AvPaa allIncl, kunFly; static JButton finn, finnPar; static JFrame vindu; static JPanel panel; static JScrollPane rulleinfo; static JTextArea info; static JTextField maxPris, minPris; static final int ANT_TRAADER = 8; static final int HASH_LENGDE = 10; public static void main (String[] args) { HashListe reiser = new HashListe(HASH_LENGDE); HashListe[] mangeReiser = new HashListe[ANT_TRAADER]; try { les("reiser.txt", reiser); lesAlle("reiser", mangeReiser); } catch (Duplikat d) { System.out.println("Flere reiser med samme navn!"); System.exit(2); } catch (FileNotFoundException e) { System.out.println("Lesefeil."); System.exit(1); } initGUI(reiser, mangeReiser); } static void initGUI (HashListe reiser, HashListe[] mangeReiser) { vindu = new JFrame("Reisebyra"); vindu.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); panel = new JPanel(); vindu.add(panel); // Minimumspris: panel.add(new JLabel("Min pris:")); minPris = new JTextField(" 0 "); panel.add(minPris); // Maksimumspris: panel.add(new JLabel("Max pris:")); maxPris = new JTextField(" 999999 "); panel.add(maxPris); // All-inclusive: allIncl = new AvPaa("Kun all-incl: ", false); class AllInclTrykk implements ActionListener { @Override public void actionPerformed (ActionEvent e) { if (allIncl.paa || ! kunFly.paa) allIncl.snu(); } } allIncl.addActionListener(new AllInclTrykk()); panel.add(allIncl); // Kun flyreiser: kunFly = new AvPaa("Kun fly: ", false); class KunFlyTrykk implements ActionListener { @Override public void actionPerformed (ActionEvent e) { if (! allIncl.paa || kunFly.paa) kunFly.snu(); } } kunFly.addActionListener(new KunFlyTrykk()); panel.add(kunFly); // Finn-knappen: finn = new JButton("Finn"); class FinnTrykk implements ActionListener { @Override public void actionPerformed (ActionEvent e) { int min = Integer.parseInt(minPris.getText().trim()); int max = Integer.parseInt(maxPris.getText().trim()); Filter f = new Filter(min, max, allIncl.paa, kunFly.paa); info.setText(null); for (Reise r: reiser) { Reise rx = f.filtrer(r); if (rx != null) info.append(r.toString() + "\n"); } } } finn.addActionListener(new FinnTrykk()); panel.add(finn); // Finn ||-knappen: finnPar = new JButton("Finn ||"); class FinnParTrykk implements ActionListener { @Override public void actionPerformed (ActionEvent e) { int min = Integer.parseInt(minPris.getText().trim()); int max = Integer.parseInt(maxPris.getText().trim()); Filter f = new Filter(min, max, allIncl.paa, kunFly.paa); Monitor mon = new Monitor(); class ParaFilter implements Runnable { HashListe mineReiser; Filter mittFilter; CountDownLatch minBar; ParaFilter (HashListe t, Filter f, CountDownLatch b) { mineReiser = t; mittFilter = f; minBar = b; } @Override public void run () { for (Reise r: mineReiser) { Reise rx = mittFilter.filtrer(r); if (rx != null) mon.settInn(rx); } minBar.countDown(); } } CountDownLatch barriere = new CountDownLatch(Reisebyra.ANT_TRAADER); for (int i = 0; i < mangeReiser.length; i++) { ParaFilter pf = new ParaFilter(mangeReiser[i], f, barriere); new Thread(pf).start(); } try { barriere.await(); } catch (InterruptedException ie) {} info.setText(null); for (Reise r: mon.data) { info.append(r.toString() + "\n"); } } } finnPar.addActionListener(new FinnParTrykk()); panel.add(finnPar); // Utskrift av resultatet: info = new JTextArea(10, 40); rulleinfo = new JScrollPane(info); panel.add(rulleinfo); vindu.pack(); vindu.setVisible(true); } static void les (String filnavn, HashListe data) throws Duplikat, FileNotFoundException { Scanner s = new Scanner(new File(filnavn)); while (s.hasNextLine()) { String[] linje = s.nextLine().split(","); String id = linje[0].trim(); int pris = Integer.parseInt(linje[1].trim()); int antall = Integer.parseInt(linje[2].trim()); Reise rx; if (linje.length == 3) rx = new Reise(id, pris, antall); else if (linje[3].trim().equals("BF")) rx = new FlyReise(id, pris, antall); else rx = new AllInclReise(id, pris, antall, Integer.parseInt(linje[4].trim())); data.settInn(id, rx); } } static void lesAlle (String prefiks, HashListe[] lister) throws Duplikat, FileNotFoundException { for (int i = 0; i < lister.length; i++) { String fNavn = prefiks + i + ".txt"; lister[i] = new HashListe(Reisebyra.HASH_LENGDE); les(fNavn, lister[i]); } } } class Reise { String navn; int pris, ledige; Reise (String id, int pr, int fri) { navn = id; pris = pr; ledige = fri; } int finnPris () { return (int)Math.round(pris * 1.25); } boolean okReise (int min, int max, boolean all, boolean bare) { return min <= finnPris() && finnPris() <= max && ! all && ! bare; } @Override public String toString () { return navn + ": kr " + finnPris() + " (" + ledige + " ledig)"; } } class AllInclReise extends Reise { int kvalitet; AllInclReise (String id, int pr, int fri, int kval) { super(id, pr, fri); kvalitet = kval; } @Override boolean okReise (int min, int max, boolean all, boolean bare) { return min <= finnPris() && finnPris() <= max && ! bare; } @Override public String toString () { String res = super.toString() + " "; for (int i = 1; i <= kvalitet; i++) res += "*"; return res; } } class FlyReise extends Reise { FlyReise (String id, int pr, int fri) { super(id, pr, fri); } @Override int finnPris () { return pris; } @Override boolean okReise (int min, int max, boolean all, boolean bare) { return min <= finnPris() && finnPris() <= max && ! all; } @Override public String toString () { return super.toString() + " [kun fly]"; } } interface Hash { int antall (); Reise fjern (String nokkel); Reise hent (String nokkel); void settInn (String nokkel, Reise reise) throws Duplikat; } class HashListe implements Hash, Iterable { Node[] alleN; HashListe (int antall) { alleN = new Node[antall]; } class Node { String nokkel; Reise reise; Node neste = null; Node (String nx, Reise r) { nokkel = nx; reise = r; } } class ReiseIterator implements Iterator { int itIndeks = -1; Node denneNode = null; ReiseIterator () { finnNeste(); } private void finnNeste () { if (denneNode != null) denneNode = denneNode.neste; while (denneNode == null) { itIndeks++; if (itIndeks >= alleN.length) return; denneNode = alleN[itIndeks]; } } @Override public Reise next () { Node res = denneNode; finnNeste(); return res.reise; } @Override public boolean hasNext () { return itIndeks < alleN.length; } } @Override public Iterator iterator () { return new ReiseIterator(); } @Override public int antall () { int n = 0; for (int i = 0; i < alleN.length; i++) for (Node p = alleN[i]; p != null; p = p.neste) n++; return n; } @Override public Reise fjern (String nokkel) { int hx = Math.abs(nokkel.hashCode()) % alleN.length; if (alleN[hx] == null) return null; if (alleN[hx].nokkel.equals(nokkel)) { Reise res = alleN[hx].reise; alleN[hx] = alleN[hx].neste; return res; } Node p1 = alleN[hx]; while (true) { Node p2 = p1.neste; if (p2 == null) return null; if (p2.nokkel.equals(nokkel)) { p1.neste = p2.neste; return p2.reise; } } } public Reise hent (String nokkel) { int hx = Math.abs(nokkel.hashCode()) % alleN.length; for (Node p = alleN[hx]; p != null; p = p.neste) if (p.nokkel.equals(nokkel)) return p.reise; return null; } @Override public void settInn (String nokkel, Reise r) throws Duplikat { int hx = Math.abs(nokkel.hashCode()) % alleN.length; Node n = new Node(nokkel, r); for (Node p = alleN[hx]; p != null; p = p.neste) if (p.nokkel.equals(nokkel)) throw new Duplikat(); n.neste = alleN[hx]; alleN[hx] = n; } } class Duplikat extends RuntimeException {} class Filter { int minPris, maxPris; boolean kunAllIncl, kunBareFly; Filter (int min, int max, boolean all, boolean bare) { minPris = min; maxPris = max; kunAllIncl = all; kunBareFly = bare; } Reise filtrer (Reise r) { if (r.okReise(minPris, maxPris, kunAllIncl, kunBareFly)) return r; else return null; } } class Monitor { HashListe data = new HashListe(Reisebyra.HASH_LENGDE); Lock laas = new ReentrantLock(); void settInn (Reise r) { laas.lock(); try { data.settInn(r.navn, r); } finally { laas.unlock(); } } }