GITHUB Coding and testing (Need somebody who knows how to use github)

profilesk2323
src.zip

src/bcccp/carpark/Carpark.java

src/bcccp/carpark/Carpark.java

package  bcccp . carpark ;

import  java . util . ArrayList ;
import  java . util . List ;

import  bcccp . tickets . adhoc . IAdhocTicket ;
import  bcccp . tickets . adhoc . IAdhocTicketDAO ;
import  bcccp . tickets . season . ISeasonTicket ;
import  bcccp . tickets . season . ISeasonTicketDAO ;

public   class   Carpark   implements   ICarpark   {
    
     private   List < ICarparkObserver >  observers ;
     private   String  carparkId ;
     private   int  capacity ;
     private   int  nParked ;
     private   IAdhocTicketDAO  adhocTicketDAO ;
     private   ISeasonTicketDAO  seasonTicketDAO ;
    
    
    
     public   Carpark ( String  name ,   int  capacity ,  
             IAdhocTicketDAO  adhocTicketDAO ,  
             ISeasonTicketDAO  seasonTicketDAO )   {
         this . carparkId  =  name ;
         this . capacity  =  capacity ;
        observers  =   new   ArrayList <> ();
         this . adhocTicketDAO  =  adhocTicketDAO ;
         this . seasonTicketDAO  =  seasonTicketDAO ;
     }

    
    
    @ Override
     public   void  register ( ICarparkObserver  observer )   {
         if   ( ! observers . contains ( observer ))   {
            observers . add ( observer );
         }
     }

    
    
    @ Override
     public   void  deregister ( ICarparkObserver  observer )   {
         if   ( observers . contains ( observer ))   {
            observers . remove ( observer );
         }
     }
    
    
    
     private   void  notifyObservers ()   {
         for   ( ICarparkObserver  observer  :  observers )   {
            observer . notifyCarparkEvent ();
         }
     }

    
    
    @ Override
     public   String  getName ()   {
         return  carparkId ;
     }
    
    
    
    @ Override
     public   boolean  isFull ()   {
         return  nParked  +  seasonTicketDAO . getNumberOfTickets ()   ==  capacity ;
     }
    
    
    
    @ Override
     public   IAdhocTicket  issueAdhocTicket ()   {
         return  adhocTicketDAO . createTicket ( carparkId );
     }
    
    
    @ Override
     public   IAdhocTicket  getAdhocTicket ( String  barcode )   {
         return  adhocTicketDAO . findTicketByBarcode ( barcode );
     }
    
    
        
    @ Override
     public   float  calculateAddHocTicketCharge ( long  entryDateTime )   {
         //TODO Implement charge logic
         return   3.0f ;
     }

    
    
    @ Override
     public   boolean  isSeasonTicketValid ( String  barcode )   {         
         ISeasonTicket  ticket  =  seasonTicketDAO . findTicketById ( barcode );
        
         // TODO implement full validation logic
         return  ticket  !=   null ;
     }

    
    
    @ Override
     public   void  registerSeasonTicket ( ISeasonTicket  seasonTicket )   {
        seasonTicketDAO . registerTicket ( seasonTicket );        
     }



    @ Override
     public   void  deregisterSeasonTicket ( ISeasonTicket  seasonTicket )   {
        seasonTicketDAO . deregisterTicket ( seasonTicket );      
     }

    
    
    @ Override
     public   void  recordSeasonTicketEntry ( String  ticketId )   {
         ISeasonTicket  ticket  =  seasonTicketDAO . findTicketById ( ticketId );
         if   ( ticket  ==   null )   throw   new   RuntimeException ( "recordSeasonTicketEntry: invalid ticketId - "   +  ticketId );
        
        seasonTicketDAO . recordTicketEntry ( ticketId );
        log ( ticket . toString ());
     }

    
    
     private   void  log ( String  message )   {
         System . out . println ( "Carpark : "   +  message );
     }



    @ Override
     public   void  recordAdhocTicketEntry ()   {
        nParked ++ ;
        
     }



    @ Override
     public   void  recordAdhocTicketExit ()   {
        nParked -- ;
        notifyObservers ();       
     }



    @ Override
     public   void  recordSeasonTicketExit ( String  ticketId )   {
         ISeasonTicket  ticket  =  seasonTicketDAO . findTicketById ( ticketId );
         if   ( ticket  ==   null )   throw   new   RuntimeException ( "recordSeasonTicketExit: invalid ticketId - "   +  ticketId );
        
        seasonTicketDAO . recordTicketExit ( ticketId );
        log ( ticket . toString ());
     }



    @ Override
     public   boolean  isSeasonTicketInUse ( String  ticketId )   {
         ISeasonTicket  ticket  =  seasonTicketDAO . findTicketById ( ticketId );
         if   ( ticket  ==   null )   throw   new   RuntimeException ( "recordSeasonTicketExit: invalid ticketId - "   +  ticketId );
        
         return  ticket . inUse ();
     }

















}

src/bcccp/carpark/CarSensor.java

src/bcccp/carpark/CarSensor.java

package  bcccp . carpark ;

import  java . awt . EventQueue ;

import  javax . swing . JFrame ;
import  javax . swing . JPanel ;
import  javax . swing . border . EmptyBorder ;
import  javax . swing . JButton ;
import  java . awt . Font ;
import  java . awt . Color ;
import  java . awt . event . ActionListener ;
import  java . util . ArrayList ;
import  java . util . List ;
import  java . awt . event . ActionEvent ;

@ SuppressWarnings ( "serial" )
public   class   CarSensor   extends   JFrame   implements   ICarSensor   {

     private   JPanel  contentPane ;
     private   boolean  carDetected ;
     private   String  detectorId ;
    
     private   List < ICarSensorResponder >  responders ;

     /**
     * Launch the application.
     */
     public   static   void  main ( String []  args )   {
         EventQueue . invokeLater ( new   Runnable ()   {
             public   void  run ()   {
                 try   {
                     CarSensor  frame  =   new   CarSensor ( "Car Detector" ,   100 ,   100 );
                    frame . setVisible ( true );
                 }   catch   ( Exception  e )   {
                    e . printStackTrace ();
                 }
             }
         });
     }

     /**
     * Create the frame.
     */
     public   CarSensor ( String  detectorId ,   int  x ,   int  y )   {
         this . detectorId  =  detectorId ;
        responders  =   new   ArrayList <> ();
        setTitle ( detectorId );
        setDefaultCloseOperation ( JFrame . EXIT_ON_CLOSE );
        setBounds ( x ,  y ,   306 ,   223 );
        contentPane  =   new   JPanel ();
        contentPane . setBorder ( new   EmptyBorder ( 5 ,   5 ,   5 ,   5 ));
        setContentPane ( contentPane );
        contentPane . setLayout ( null );
        
        carDetected  =   false ;
         JButton  detectorButton  =   new   JButton ();
        detectorButton . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        detectorButton . setBounds ( 28 ,   24 ,   238 ,   135 );
        detectorButton . addActionListener ( new   ActionListener ()   {
             public   void  actionPerformed ( ActionEvent  e )   {
                carDetected  =   ! carDetected ;
                 if   ( carDetected )   {
                    detectorButton . setBackground ( Color . GREEN );
                    detectorButton . setText ( "Car Detected" );
                 }
                 else   {
                    detectorButton . setBackground ( Color . RED );
                    detectorButton . setText ( "No Car Detected" );
                 }
                 for   ( ICarSensorResponder  responder  :  responders  )   {
                    responder . carEventDetected ( detectorId ,  carDetected );
                 }
             }
         });
        detectorButton . setBackground ( Color . RED );
        detectorButton . setText ( "No Car Detected" );
        contentPane . add ( detectorButton );
     }
    
     public   void  registerResponder ( ICarSensorResponder  responder )   {
         if   ( ! responders . contains ( responder ))   {
            responders . add ( responder );
         }
     }
    
     public   void  deregisterResponder ( ICarSensorResponder  responder )   {
         if   ( responders . contains ( responder ))   {
            responders . remove ( responder );
         }
     }

    @ Override
     public   String  getId ()   {
         return  detectorId ;
     }

    @ Override
     public   boolean  carIsDetected ()   {
         return  carDetected ;
     }
    
    

}

src/bcccp/carpark/entry/EntryController.java

src/bcccp/carpark/entry/EntryController.java

package  bcccp . carpark . entry ;

import  bcccp . carpark . Carpark ;
import  bcccp . carpark . ICarSensor ;
import  bcccp . carpark . ICarSensorResponder ;
import  bcccp . carpark . ICarpark ;
import  bcccp . carpark . ICarparkObserver ;
import  bcccp . carpark . IGate ;
import  bcccp . tickets . adhoc . IAdhocTicket ;

public   class   EntryController  
         implements   ICarSensorResponder ,
                    ICarparkObserver ,
                    IEntryController   {
    
     private  enum STATE  {  IDLE ,  WAITING ,  FULL ,  VALIDATED ,  ISSUED ,  TAKEN ,  ENTERING ,  ENTERED ,  BLOCKED  }  
    
     private  STATE state_ ;
     private  STATE prevState_ ;
     private   String  message ;
    
     private   IGate  entryGate_ ;
     private   ICarSensor  outsideEntrySensor_ ;  
     private   ICarSensor  insideEntrySensor_ ;
     private   IEntryUI  ui ;
    
     private   ICarpark  carpark ;
     private   IAdhocTicket   adhocTicket  =   null ;
     private   long  entryTime ;
     private   String  seasonTicketId  =   null ;
    
    

     public   EntryController ( Carpark  carpark ,   IGate  entryGate ,  
             ICarSensor  os ,  
             ICarSensor  is ,
             IEntryUI  ui )   {
        
         this . carpark  =  carpark ;
         this . entryGate_  =  entryGate ;
         this . outsideEntrySensor_  =  os ;
         this . insideEntrySensor_  =  is ;
         this . ui  =  ui ;
        
        outsideEntrySensor_ . registerResponder ( this );
        insideEntrySensor_ . registerResponder ( this );
        ui . registerController ( this );
        
        setState ( STATE . IDLE );
        
     }

    
    
     private   void  log ( String  message )   {
         System . out . println ( "EntryController : "   +  message );
     }



    @ Override
     public   void  carEventDetected ( String  detectorId ,   boolean  carDetected )   {

        log ( "carEventDetected: "   +  detectorId  +   ", car Detected: "   +  carDetected  );
        
         switch   ( state_ )   {
        
         case  BLOCKED :  
             if   ( detectorId . equals ( insideEntrySensor_ . getId ())   &&   ! carDetected )   {
                setState ( prevState_ );
             }
             break ;
            
         case  IDLE :  
            log ( "eventDetected: IDLE" );
             if   ( detectorId . equals ( outsideEntrySensor_ . getId ())   &&  carDetected )   {
                log ( "eventDetected: setting state to WAITING" );
                setState ( STATE . WAITING );
             }
             else   if   ( detectorId . equals ( insideEntrySensor_ . getId ())   &&  carDetected )   {
                setState ( STATE . BLOCKED );
             }
             break ;
            
         case  WAITING :  
         case  FULL :  
         case  VALIDATED :  
         case  ISSUED :  
             if   ( detectorId . equals ( outsideEntrySensor_ . getId ())   &&   ! carDetected )   {
                setState ( STATE . IDLE );
             }
             else   if   ( detectorId . equals ( insideEntrySensor_ . getId ())   &&  carDetected )   {
                setState ( STATE . BLOCKED );
             }
             break ;
            
         case  TAKEN :  
             if   ( detectorId . equals ( outsideEntrySensor_ . getId ())   &&   ! carDetected )   {
                setState ( STATE . IDLE );
             }
             else   if   ( detectorId . equals ( insideEntrySensor_ . getId ())   &&  carDetected )   {
                setState ( STATE . ENTERING );
             }
             break ;
            
         case  ENTERING :  
             if   ( detectorId . equals ( outsideEntrySensor_ . getId ())   &&   ! carDetected )   {
                setState ( STATE . ENTERED );
             }
             else   if   ( detectorId . equals ( insideEntrySensor_ . getId ())   &&   ! carDetected )   {
                setState ( STATE . TAKEN );
             }
             break ;
            
         case  ENTERED :  
             if   ( detectorId . equals ( outsideEntrySensor_ . getId ())   &&  carDetected )   {
                setState ( STATE . ENTERING );
             }
             else   if   ( detectorId . equals ( insideEntrySensor_ . getId ())   &&   ! carDetected )   {
                setState ( STATE . IDLE );
             }
             break ;
            
         default :  
             break ;
            
         }
        
     }

    
    
     private   void  setState ( STATE newState )   {
         switch   ( newState )   {
        
         case  BLOCKED :  
            log ( "setState: BLOCKED" );
            prevState_  =  state_ ;
            state_  =  STATE . BLOCKED ;
            message  =   "Blocked" ;
            ui . display ( message );
             break ;
            
         case  IDLE :  
            log ( "setState: IDLE" );
             if   ( prevState_  ==  STATE . ENTERED )   {
                 if   ( adhocTicket  !=   null )   {
                    adhocTicket . enter ( entryTime );
                    carpark . recordAdhocTicketEntry ();
                    entryTime  =   0 ;
                    log ( adhocTicket . toString ()   );
                    adhocTicket  =   null ;
                 }
                 else   if   ( seasonTicketId  !=   null )   {
                    carpark . recordSeasonTicketEntry ( seasonTicketId );
                    seasonTicketId  =   null ;
                 }
             }
            message  =   "Idle" ;
            state_  =  STATE . IDLE ;
            prevState_  =  state_ ;
            ui . display ( message );
             if   ( outsideEntrySensor_ . carIsDetected ())   {
                setState ( STATE . WAITING );
             }
             if   ( entryGate_ . isRaised ())   {
                entryGate_ . lower ();
             }
            ui . discardTicket ();
             break ;
            
         case  WAITING :  
            log ( "setState: WAITING" );
            message  =   "Push Button" ;
            state_  =  STATE . WAITING ;
            prevState_  =  state_ ;
            ui . display ( message );
             if   ( ! outsideEntrySensor_ . carIsDetected ())   {
                setState ( STATE . IDLE );
             }
             break ;
            
         case  FULL :  
            log ( "setState: FULL" );
            message  =   "Carpark Full" ;
            state_  =  STATE . FULL ;
            prevState_  =  state_ ;
            ui . display ( message );
             break ;
            
         case  VALIDATED :  
            log ( "setState: VALIDATED" );
            message  =   "Ticket Validated" ;
            state_  =  STATE . VALIDATED ;
            prevState_  =  state_ ;
            ui . display ( message );
             if   ( ! outsideEntrySensor_ . carIsDetected ())   {
                setState ( STATE . IDLE );
             }
             break ;
            
         case  ISSUED :  
            log ( "setState: ISSUED" );
            message  =   "Take Ticket" ;
            state_  =  STATE . ISSUED ;
            prevState_  =  state_ ;
            ui . display ( message );
             if   ( ! outsideEntrySensor_ . carIsDetected ())   {
                setState ( STATE . IDLE );
             }
             break ;
            
         case  TAKEN :  
            log ( "setState: TAKEN" );
            message  =   "Ticket Taken" ;
            state_  =  STATE . TAKEN ;
            prevState_  =  state_ ;
            ui . display ( message );
            entryGate_ . raise ();
             break ;
            
         case  ENTERING :  
            log ( "setState: ENTERING" );
            message  =   "Entering" ;
            state_  =  STATE . ENTERING ;
            prevState_  =  state_ ;
            ui . display ( message );
             break ;
            
         case  ENTERED :  
            log ( "setState: ENTERED" );
            message  =   "Entered" ;
            state_  =  STATE . ENTERED ;
            prevState_  =  state_ ;
            ui . display ( message );
             break ;
            
         default :  
             break ;
            
         }
                
     }

    
    
    @ Override
     public   void  buttonPushed ()   {
         if   ( state_  ==  STATE . WAITING )   {
             if   ( ! carpark . isFull ())   {
                adhocTicket  =  carpark . issueAdhocTicket ();
                
                 String  carparkId  =  adhocTicket . getCarparkId ();
                 int  ticketNo  =  adhocTicket . getTicketNo ();
                entryTime  =   System . currentTimeMillis ();
                 //entryTime = adhocTicket.getEntryDateTime();
                 String  barcode  =  adhocTicket . getBarcode ();
                
                ui . printTicket ( carparkId ,  ticketNo ,  entryTime ,  barcode );
                setState ( STATE . ISSUED );
             }
             else   {
                setState ( STATE . FULL );
             }
         }
         else   {
            ui . beep ();
            log ( "ButtonPushed: called while in incorrect state" );
         }
        
     }

    
    
    @ Override
     public   void  ticketInserted ( String  barcode )   {
         if   ( state_  ==  STATE . WAITING )   {
             try   {
                 if   ( carpark . isSeasonTicketValid ( barcode )   &&
                     ! carpark . isSeasonTicketInUse ( barcode ))   {
                     this . seasonTicketId  =  barcode ;
                    setState ( STATE . VALIDATED );
                 }
                 else   {
                    ui . beep ();
                    seasonTicketId  =   null ;
                    log ( "ticketInserted: invalid ticket id" );                
                 }
             }
             catch   ( NumberFormatException  e )   {
                ui . beep ();
                seasonTicketId  =   null ;
                log ( "ticketInserted: invalid ticket id" );                
             }
         }
         else   {
            ui . beep ();
            log ( "ticketInserted: called while in incorrect state" );
         }
        
     }
    
    
    
    @ Override
     public   void  ticketTaken ()   {
         if   ( state_  ==  STATE . ISSUED  ||  state_  ==  STATE . VALIDATED  )   {
            setState ( STATE . TAKEN );
         }
         else   {
            ui . beep ();
            log ( "ticketTaken: called while in incorrect state" );
         }
        
     }



    @ Override
     public   void  notifyCarparkEvent ()   {
         if   ( state_  ==  STATE . FULL )   {
             if   ( ! carpark . isFull ())   {
                setState ( STATE . WAITING );
             }
         }
        
     }

    

}

src/bcccp/carpark/entry/EntryUI.java

src/bcccp/carpark/entry/EntryUI.java

package  bcccp . carpark . entry ;

import  java . awt . EventQueue ;

import  javax . swing . JFrame ;
import  javax . swing . JPanel ;
import  javax . swing . border . EmptyBorder ;
import  javax . swing . border . TitledBorder ;
import  javax . swing . JTextField ;
import  java . awt . Font ;
import  java . awt . Toolkit ;

import  javax . swing . SwingConstants ;
import  javax . swing . JButton ;
import  java . awt . event . ActionListener ;
import  java . util . Date ;
import  java . awt . event . ActionEvent ;
import  javax . swing . JTextArea ;
import  java . awt . Color ;

@ SuppressWarnings ( "serial" )
public   class   EntryUI   extends   JFrame   implements   IEntryUI   {

     private   JPanel  contentPane ;
     private   JTextField  displayTextField ;
     private   JTextField  seasonTicketTextField ;
     private   IEntryController  controller ;
     private   JTextArea  ticketPrinterTextArea ;

    
    
     /**
     * Launch the application.
     */
     public   static   void  main ( String []  args )   {
         EventQueue . invokeLater ( new   Runnable ()   {
             public   void  run ()   {
                 try   {
                     EntryUI  frame  =   new   EntryUI ( 100 ,   100 );
                    frame . setVisible ( true );
                 }   catch   ( Exception  e )   {
                    e . printStackTrace ();
                 }
             }
         });
     }

    
    
     /**
     * Create the frame.
     */
     public   EntryUI ( int  x ,   int  y )   {
        setTitle ( "Entry Pillar UI" );
        setDefaultCloseOperation ( JFrame . EXIT_ON_CLOSE );
        setBounds ( x ,  y ,   340 ,   710 );
        contentPane  =   new   JPanel ();
        contentPane . setBorder ( new   EmptyBorder ( 5 ,   5 ,   5 ,   5 ));
        setContentPane ( contentPane );
        contentPane . setLayout ( null );
        
         JPanel  panel  =   new   JPanel ();
        panel . setBorder ( new   TitledBorder ( null ,   "LCD Display" ,   TitledBorder . LEADING ,   TitledBorder . TOP ,   null ,   null ));
        panel . setBounds ( 10 ,   11 ,   306 ,   106 );
        contentPane . add ( panel );
        panel . setLayout ( null );
        
        displayTextField  =   new   JTextField ();
        displayTextField . setHorizontalAlignment ( SwingConstants . CENTER );
         //displayTextField.setText("Push Button");
        displayTextField . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   32 ));
        displayTextField . setEditable ( false );
        displayTextField . setBounds ( 10 ,   15 ,   288 ,   82 );
        panel . add ( displayTextField );
        displayTextField . setColumns ( 10 );
        
         JButton  issueAdhocTicketButton  =   new   JButton ( "Issue Adhoc Ticket" );
        issueAdhocTicketButton . addActionListener ( new   ActionListener ()   {
             public   void  actionPerformed ( ActionEvent  e )   {
                pushButton ();
             }

         });
        issueAdhocTicketButton . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        issueAdhocTicketButton . setBounds ( 15 ,   119 ,   287 ,   46 );
        contentPane . add ( issueAdhocTicketButton );
        
         JPanel  panel_1  =   new   JPanel ();
        panel_1 . setBorder ( new   TitledBorder ( null ,   "Season Ticket Reader" ,   TitledBorder . LEADING ,   TitledBorder . TOP ,   null ,   null ));
        panel_1 . setBounds ( 10 ,   176 ,   306 ,   153 );
        contentPane . add ( panel_1 );
        panel_1 . setLayout ( null );
        
        seasonTicketTextField  =   new   JTextField ();
        seasonTicketTextField . setHorizontalAlignment ( SwingConstants . CENTER );
        seasonTicketTextField . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        seasonTicketTextField . setBounds ( 10 ,   21 ,   285 ,   53 );
        panel_1 . add ( seasonTicketTextField );
        seasonTicketTextField . setColumns ( 10 );
        
         JButton  btnNewButton  =   new   JButton ( "Validate Season Ticket" );
        btnNewButton . addActionListener ( new   ActionListener ()   {
             public   void  actionPerformed ( ActionEvent  arg0 )   {
                insertTicket ();
             }
         });
        btnNewButton . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        btnNewButton . setBounds ( 10 ,   85 ,   285 ,   45 );
        panel_1 . add ( btnNewButton );
        
         JPanel  panel_2  =   new   JPanel ();
        panel_2 . setBorder ( new   TitledBorder ( null ,   "Entry Ticket Printer" ,   TitledBorder . LEADING ,   TitledBorder . TOP ,   null ,   null ));
        panel_2 . setBounds ( 5 ,   340 ,   311 ,   321 );
        contentPane . add ( panel_2 );
        panel_2 . setLayout ( null );
        
        ticketPrinterTextArea  =   new   JTextArea ();
        ticketPrinterTextArea . setBackground ( Color . LIGHT_GRAY );
        ticketPrinterTextArea . setText ( "" );
        ticketPrinterTextArea . setRows ( 10 );
        ticketPrinterTextArea . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   14 ));
        ticketPrinterTextArea . setEditable ( false );
        ticketPrinterTextArea . setBounds ( 10 ,   22 ,   285 ,   230 );
        panel_2 . add ( ticketPrinterTextArea );
        
         JButton  btnNewButton_1  =   new   JButton ( "Take Ticket" );
        btnNewButton_1 . addActionListener ( new   ActionListener ()   {
             public   void  actionPerformed ( ActionEvent  e )   {
                takeTicket ();
             }
         });
        btnNewButton_1 . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        btnNewButton_1 . setBounds ( 10 ,   263 ,   285 ,   45 );
        panel_2 . add ( btnNewButton_1 );
     }

    
    
    @ Override
     public   void  registerController ( IEntryController  controller )   {
         this . controller  =  controller ;
     }

    
    
    @ Override
     public   void  deregisterController ()   {
         this . controller  =   null ;  
     }
    
    
    
    @ Override
     public   void  display ( String  message )   {
        displayTextField . setText ( message );   
     }

    
    
    @ Override
     public   void  beep ()   {
         Toolkit . getDefaultToolkit (). beep ();  
     }
    
    
    
     private   void  pushButton ()   {
        log ( "pushButton : calling button pushed" );
        controller . buttonPushed ();   
     }

    
    
     private   void  insertTicket ()   {
         String  ticketStr  =  seasonTicketTextField . getText ();
        controller . ticketInserted ( ticketStr );    
     }
    
    
    
     private   void  takeTicket ()   {
        controller . ticketTaken ();
        ticketPrinterTextArea . setText ( "" );
        seasonTicketTextField . setText ( "" );
     }

    
    
     private   void  log ( String  message )   {
         System . out . println ( "EntryUI : "   +  message );
     }

    
    
    @ Override
     public   void  printTicket ( String  carparkId ,   int  tNo ,   long  datetime ,   String  barcode )   {
         Date  entryDate  =   new   Date ( datetime );
         StringBuilder  builder  =   new   StringBuilder ();
        builder . append ( "Carpark    : "   +  carparkId  +   "\n" );
        builder . append ( "Ticket No  : "   +  tNo  +   "\n" );
        builder . append ( "Entry Time : "   +  entryDate  +   "\n" );
        builder . append ( "Barcode    : "   +  barcode  +   "\n" );
        
        ticketPrinterTextArea . setText ( builder . toString ());           
     }

    
    
    @ Override
     public   void  discardTicket ()   {
        seasonTicketTextField . setText ( "" );
        ticketPrinterTextArea . setText ( "" );   
     }

    
    
    @ Override
     public   boolean  ticketPrinted ()   {
         return  ticketPrinterTextArea . getText (). length ()   !=   0 ;
     }


}

src/bcccp/carpark/entry/IEntryController.java

src/bcccp/carpark/entry/IEntryController.java

package  bcccp . carpark . entry ;

public   interface   IEntryController   {
    
     public   void  buttonPushed ();
     public   void  ticketInserted ( String  barcode );
     public   void  ticketTaken ();

}

src/bcccp/carpark/entry/IEntryUI.java

src/bcccp/carpark/entry/IEntryUI.java

package  bcccp . carpark . entry ;

public   interface   IEntryUI   {
     public   void  registerController ( IEntryController  controller );
     public   void  deregisterController ();
    
     public   void  display ( String  message );
     public   void  printTicket ( String  id ,   int  tNo ,   long  entryDatetime ,   String  barcode );
     public   boolean  ticketPrinted ();
     public   void  discardTicket ();
     public   void  beep ();

}

src/bcccp/carpark/exit/ExitController.java

src/bcccp/carpark/exit/ExitController.java

package  bcccp . carpark . exit ;

import  bcccp . carpark . Carpark ;
import  bcccp . carpark . ICarSensor ;
import  bcccp . carpark . ICarSensorResponder ;
import  bcccp . carpark . ICarpark ;
import  bcccp . carpark . IGate ;
import  bcccp . tickets . adhoc . IAdhocTicket ;

public   class   ExitController  
         implements   ICarSensorResponder ,
                    IExitController   {
    
     private  enum STATE  {  IDLE ,  WAITING ,  PROCESSED ,  REJECTED ,  TAKEN ,  EXITING ,  EXITED ,  BLOCKED  }  
    
     private  STATE state ;
     private  STATE prevState ;
     private   String  message ;
     //private String prevMessage;
    
     private   IGate  exitGate ;
     private   ICarSensor  is ;
     private   ICarSensor  os ;  
     private   IExitUI  ui ;
    
     private   ICarpark  carpark ;
     private   IAdhocTicket   adhocTicket  =   null ;
     private   long  exitTime ;
     private   String  seasonTicketId  =   null ;
    
    

     public   ExitController ( Carpark  carpark ,   IGate  exitGate ,  
             ICarSensor  is ,
             ICarSensor  os ,  
             IExitUI  ui )   {
        
         this . carpark  =  carpark ;
         this . exitGate  =  exitGate ;
         this . is  =  is ;
         this . os  =  os ;
         this . ui  =  ui ;
        
        os . registerResponder ( this );
        is . registerResponder ( this );
        ui . registerController ( this );

        prevState  =  STATE . IDLE ;      
        setState ( STATE . IDLE );        
     }

    
    
     private   void  log ( String  message )   {
         System . out . println ( "ExitController : "   +  message );
     }



    @ Override
     public   void  carEventDetected ( String  detectorId ,   boolean  carDetected )   {

        log ( "carEventDetected: "   +  detectorId  +   ", car Detected: "   +  carDetected  );
        
         switch   ( state )   {
        
         case  BLOCKED :  
             if   ( detectorId . equals ( is . getId ())   &&   ! carDetected )   {
                setState ( prevState );
             }
             break ;
            
         case  IDLE :  
            log ( "eventDetected: IDLE" );
             if   ( detectorId . equals ( is . getId ())   &&  carDetected )   {
                log ( "eventDetected: setting state to WAITING" );
                setState ( STATE . WAITING );
             }
             else   if   ( detectorId . equals ( os . getId ())   &&  carDetected )   {
                setState ( STATE . BLOCKED );
             }
             break ;
            
         case  WAITING :  
         case  PROCESSED :  
             if   ( detectorId . equals ( is . getId ())   &&   ! carDetected )   {
                setState ( STATE . IDLE );
             }
             else   if   ( detectorId . equals ( os . getId ())   &&  carDetected )   {
                setState ( STATE . BLOCKED );
             }
             break ;
            
         case  TAKEN :  
             if   ( detectorId . equals ( is . getId ())   &&   ! carDetected )   {
                setState ( STATE . IDLE );
             }
             else   if   ( detectorId . equals ( os . getId ())   &&  carDetected )   {
                setState ( STATE . EXITING );
             }
             break ;
            
         case  EXITING :  
             if   ( detectorId . equals ( is . getId ())   &&   ! carDetected )   {
                setState ( STATE . EXITED );
             }
             else   if   ( detectorId . equals ( os . getId ())   &&   ! carDetected )   {
                setState ( STATE . TAKEN );
             }
             break ;
            
         case  EXITED :  
             if   ( detectorId . equals ( is . getId ())   &&  carDetected )   {
                setState ( STATE . EXITING );
             }
             else   if   ( detectorId . equals ( os . getId ())   &&   ! carDetected )   {
                setState ( STATE . IDLE );
             }
             break ;
            
         default :  
             break ;
            
         }
        
     }

    
    
     private   void  setState ( STATE newState )   {
         switch   ( newState )   {
        
         case  BLOCKED :  
            log ( "setState: BLOCKED" );
            prevState  =  state ;
             //prevMessage = message;
            state  =  STATE . BLOCKED ;
            message  =   "Blocked" ;
            ui . display ( message );
             break ;
            
         case  IDLE :  
            log ( "setState: IDLE" );
             if   ( prevState  ==  STATE . EXITED )   {
                 if   ( adhocTicket  !=   null )   {
                    adhocTicket . exit ( exitTime );
                    carpark . recordAdhocTicketExit ();
                    log ( adhocTicket . toString ()   );
                 }
                 else   if   ( seasonTicketId  !=   null )   {
                    carpark . recordSeasonTicketExit ( seasonTicketId );
                 }
             }
            adhocTicket  =   null ;
            seasonTicketId  =   null ;
            
            message  =   "Idle" ;
            state  =  STATE . IDLE ;
             //prevMessage = message;
            prevState  =  state ;
            ui . display ( message );
             if   ( is . carIsDetected ())   {
                setState ( STATE . WAITING );
             }
             if   ( exitGate . isRaised ())   {
                exitGate . lower ();
             }
            exitTime  =   0 ;
             break ;
            
         case  WAITING :  
            log ( "setState: WAITING" );
            message  =   "Insert Ticket" ;
            state  =  STATE . WAITING ;
             //prevMessage = message;
            prevState  =  state ;
            ui . display ( message );
             if   ( ! is . carIsDetected ())   {
                setState ( STATE . IDLE );
             }
             break ;
            
         case  PROCESSED :  
            log ( "setState: PROCESSED" );
            message  =   "Take Processed Ticket" ;
            state  =  STATE . PROCESSED ;
             //prevMessage = message;
            prevState  =  state ;
            ui . display ( message );
             if   ( ! is . carIsDetected ())   {
                setState ( STATE . IDLE );
             }
             break ;
            
         case  REJECTED :  
            log ( "setState: REJECTED" );
            message  =   "Take Rejected Ticket" ;
            state  =  STATE . REJECTED ;
             //prevMessage = message;
            prevState  =  state ;
            ui . display ( message );
             if   ( ! is . carIsDetected ())   {
                setState ( STATE . IDLE );
             }
             break ;
            
         case  TAKEN :  
            log ( "setState: TAKEN" );
            message  =   "Ticket Taken" ;
            state  =  STATE . TAKEN ;
             //prevMessage = message;
            prevState  =  state ;
            ui . display ( message );
             break ;
            
         case  EXITING :  
            log ( "setState: EXITING" );
            message  =   "Exiting" ;
            state  =  STATE . EXITING ;
             //prevMessage = message;
            prevState  =  state ;
            ui . display ( message );
             break ;
            
         case  EXITED :  
            log ( "setState: EXITED" );
            message  =   "Exited" ;
            state  =  STATE . EXITED ;
             //prevMessage = message;
            prevState  =  state ;
            ui . display ( message );
             break ;
            
         default :  
             break ;
            
         }
                
     }

    
    
     private   boolean  isAdhocTicket ( String  barcode )   {
         return  barcode . substring ( 0 , 1 ). equals ( "A" );
     }
    
    
    
    @ Override
     public   void  ticketInserted ( String  ticketStr )   {
         if   ( state  ==  STATE . WAITING )   {
             if   ( isAdhocTicket ( ticketStr ))   {
                adhocTicket  =  carpark . getAdhocTicket ( ticketStr );
                exitTime  =   System . currentTimeMillis ();
                 if   ( adhocTicket  !=   null   &&  adhocTicket . isPaid ())   {
                    setState ( STATE . PROCESSED );
                 }
                 else   {
                    ui . beep ();
                    setState ( STATE . REJECTED );                        
                 }
             }
             else   if   ( carpark . isSeasonTicketValid ( ticketStr )   &&
                     carpark . isSeasonTicketInUse ( ticketStr )){                    
                seasonTicketId  =  ticketStr ;
                setState ( STATE . PROCESSED );
             }
             else   {
                ui . beep ();
                setState ( STATE . REJECTED );                        
             }
         }
         else   {
            ui . beep ();
            ui . discardTicket ();
            log ( "ticketInserted: called while in incorrect state" );
            setState ( STATE . REJECTED );                        
         }
        
     }
    
    
    
    @ Override
     public   void  ticketTaken ()   {
         if   ( state  ==  STATE . PROCESSED )    {
            exitGate . raise ();
            setState ( STATE . TAKEN );
         }
         else   if   ( state  ==  STATE . REJECTED )   {
            setState ( STATE . WAITING );
         }
         else   {
            ui . beep ();
            log ( "ticketTaken: called while in incorrect state" );
         }
        
     }




    

}

src/bcccp/carpark/exit/ExitUI.java

src/bcccp/carpark/exit/ExitUI.java

package  bcccp . carpark . exit ;

import  java . awt . EventQueue ;

import  javax . swing . JFrame ;
import  javax . swing . JPanel ;
import  javax . swing . border . EmptyBorder ;
import  javax . swing . border . TitledBorder ;

import  javax . swing . JTextField ;
import  java . awt . Font ;
import  java . awt . Toolkit ;

import  javax . swing . SwingConstants ;
import  javax . swing . JButton ;
import  java . awt . event . ActionListener ;
import  java . awt . event . ActionEvent ;
import  java . awt . Color ;
import  javax . swing . UIManager ;

@ SuppressWarnings ( "serial" )
public   class   ExitUI   extends   JFrame   implements   IExitUI   {

     private   JPanel  contentPane ;
     private   JTextField  displayTextField ;
     private   JTextField  ticketReaderTextField ;
     private   IExitController  controller ;

    
    
     /**
     * Launch the application.
     */
     public   static   void  main ( String []  args )   {
         EventQueue . invokeLater ( new   Runnable ()   {
             public   void  run ()   {
                 try   {
                     ExitUI  frame  =   new   ExitUI ( 100 ,   100 );
                    frame . setVisible ( true );
                 }   catch   ( Exception  e )   {
                    e . printStackTrace ();
                 }
             }
         });
     }

    
    
     /**
     * Create the frame.
     */
     public   ExitUI ( int  x ,   int  y )   {
        setTitle ( "Exit Pillar UI" );
        setDefaultCloseOperation ( JFrame . EXIT_ON_CLOSE );
        setBounds ( x ,  y ,   340 ,   380 );
        contentPane  =   new   JPanel ();
        contentPane . setBorder ( new   EmptyBorder ( 5 ,   5 ,   5 ,   5 ));
        setContentPane ( contentPane );
        contentPane . setLayout ( null );
        
         JPanel  panel  =   new   JPanel ();
        panel . setBorder ( new   TitledBorder ( null ,   "LCD Display" ,   TitledBorder . LEADING ,   TitledBorder . TOP ,   null ,   null ));
        panel . setBounds ( 5 ,   5 ,   316 ,   106 );
        contentPane . add ( panel );
        panel . setLayout ( null );
        
        displayTextField  =   new   JTextField ();
        displayTextField . setHorizontalAlignment ( SwingConstants . CENTER );
         //displayTextField.setText("Push Button");
        displayTextField . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   28 ));
        displayTextField . setEditable ( false );
        displayTextField . setBounds ( 10 ,   15 ,   296 ,   82 );
        panel . add ( displayTextField );
        displayTextField . setColumns ( 10 );
        
         JPanel  panel_1  =   new   JPanel ();
        panel_1 . setBorder ( new   TitledBorder ( UIManager . getBorder ( "TitledBorder.border" ),   "Ticket Reader" ,   TitledBorder . LEADING ,   TitledBorder . TOP ,   null ,   new   Color ( 0 ,   0 ,   0 )));
        panel_1 . setBounds ( 15 ,   115 ,   306 ,   153 );
        contentPane . add ( panel_1 );
        panel_1 . setLayout ( null );
        
        ticketReaderTextField  =   new   JTextField ();
        ticketReaderTextField . setHorizontalAlignment ( SwingConstants . CENTER );
        ticketReaderTextField . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        ticketReaderTextField . setBounds ( 10 ,   21 ,   285 ,   53 );
        panel_1 . add ( ticketReaderTextField );
        ticketReaderTextField . setColumns ( 10 );
        
         JButton  btnNewButton  =   new   JButton ( "Read Ticket" );
        btnNewButton . addActionListener ( new   ActionListener ()   {
             public   void  actionPerformed ( ActionEvent  arg0 )   {
                readTicket ();
             }
         });
        btnNewButton . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        btnNewButton . setBounds ( 10 ,   85 ,   285 ,   45 );
        panel_1 . add ( btnNewButton );
        
         JButton  btnNewButton_1  =   new   JButton ( "Take Ticket" );
        btnNewButton_1 . setBounds ( 25 ,   279 ,   285 ,   45 );
        contentPane . add ( btnNewButton_1 );
        btnNewButton_1 . addActionListener ( new   ActionListener ()   {
             public   void  actionPerformed ( ActionEvent  e )   {
                takeTicket ();
             }
         });
        btnNewButton_1 . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
     }

    
    
    @ Override
     public   void  registerController ( IExitController  controller )   {
         this . controller  =  controller ;
     }

    
    
    @ Override
     public   void  deregisterController ()   {
         this . controller  =   null ;  
     }
    
    
    
    @ Override
     public   void  display ( String  message )   {
        displayTextField . setText ( message );   
     }

    
    
    @ Override
     public   void  beep ()   {
         Toolkit . getDefaultToolkit (). beep ();  
     }

    
    
     private   void  readTicket ()   {
         String  ticketStr  =  ticketReaderTextField . getText ();
        controller . ticketInserted ( ticketStr );    
     }
    
    
    
     private   void  takeTicket ()   {
        controller . ticketTaken ();
        ticketReaderTextField . setText ( "" );
     }

    
    
    @ SuppressWarnings ( "unused" )
     private   void  log ( String  message )   {
         System . out . println ( "EntryUI : "   +  message );
     }

    
    
    
    @ Override
     public   void  discardTicket ()   {
        ticketReaderTextField . setText ( "" );
     }

    
}

src/bcccp/carpark/exit/IExitController.java

src/bcccp/carpark/exit/IExitController.java

package  bcccp . carpark . exit ;

public   interface   IExitController   {
     public   void  ticketInserted ( String  ticketStr );
     public   void  ticketTaken ();

}

src/bcccp/carpark/exit/IExitUI.java

src/bcccp/carpark/exit/IExitUI.java

package  bcccp . carpark . exit ;

public   interface   IExitUI   {

     public   void  registerController ( IExitController  controller );
     public   void  deregisterController ();
     public   void  display ( String  message );
     public   void  beep ();
     public   void  discardTicket ();     
    
}

src/bcccp/carpark/Gate.java

src/bcccp/carpark/Gate.java

package  bcccp . carpark ;

import  java . awt . EventQueue ;

import  javax . swing . JFrame ;
import  javax . swing . JPanel ;
import  javax . swing . border . EmptyBorder ;
import  javax . swing . JTextField ;
import  java . awt . Font ;
import  javax . swing . SwingConstants ;
import  java . awt . Color ;

@ SuppressWarnings ( "serial" )
public   class   Gate   extends   JFrame   implements   IGate   {

     private   JPanel  contentPane ;
     private   JTextField  gateStatusTextField ;
     private   boolean  raised ;

     /**
     * Launch the application.
     */
     public   static   void  main ( String []  args )   {
         Gate  frame  =   new   Gate ( 100 ,   100 );
         EventQueue . invokeLater ( new   Runnable ()   {
             public   void  run ()   {
                 try   {
                    frame . setVisible ( true );
                 }   catch   ( Exception  e )   {
                    e . printStackTrace ();
                 }
             }
         });
         try   {
             Thread . sleep ( 2000 );
            frame . raise ();
             Thread . sleep ( 2000 );
            frame . lower ();           
         }
         catch   ( InterruptedException  e )   {}
     }

     /**
     * Create the frame.
     */
     public   Gate ( int  x ,   int  y )   {
        setTitle ( "Gate" );
        setDefaultCloseOperation ( JFrame . EXIT_ON_CLOSE );
        setBounds ( x ,  y ,   310 ,   116 );
        contentPane  =   new   JPanel ();
        contentPane . setBorder ( new   EmptyBorder ( 5 ,   5 ,   5 ,   5 ));
        setContentPane ( contentPane );
        contentPane . setLayout ( null );
        
        gateStatusTextField  =   new   JTextField ();
        gateStatusTextField . setBackground ( Color . RED );
        gateStatusTextField . setEditable ( false );
        gateStatusTextField . setHorizontalAlignment ( SwingConstants . CENTER );
        gateStatusTextField . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        gateStatusTextField . setText ( "Gate Down" );
        gateStatusTextField . setBounds ( 5 ,   5 ,   279 ,   64 );
        contentPane . add ( gateStatusTextField );
        gateStatusTextField . setColumns ( 10 );
     }

    
    
    @ Override
     public   void  raise ()   {
        gateStatusTextField . setBackground ( Color . GREEN );
        gateStatusTextField . setText ( "Gate Up" );
        raised  =   true ;       
     }

    
    
    @ Override
     public   void  lower ()   {
        gateStatusTextField . setBackground ( Color . RED );
        gateStatusTextField . setText ( "Gate Down" );
        raised  =   false ;      
     }

    
    
    @ Override
     public   boolean  isRaised ()   {
         return  raised ;
     }

    
}

src/bcccp/carpark/ICarpark.java

src/bcccp/carpark/ICarpark.java

package  bcccp . carpark ;

import  bcccp . tickets . adhoc . IAdhocTicket ;
import  bcccp . tickets . season . ISeasonTicket ;

public   interface   ICarpark   {
    
     public   void  register ( ICarparkObserver  observer );
     public   void  deregister ( ICarparkObserver  observer );
     public   String  getName ();
     public   boolean  isFull ();
    
     public   IAdhocTicket  issueAdhocTicket ();
     public   void  recordAdhocTicketEntry ();
     public   IAdhocTicket  getAdhocTicket ( String  barcode );
     public   float  calculateAddHocTicketCharge ( long  entryDateTime );
     public   void  recordAdhocTicketExit ();
    
     public   void  registerSeasonTicket ( ISeasonTicket  seasonTicket );
     public   void  deregisterSeasonTicket ( ISeasonTicket  seasonTicket );

     public   boolean  isSeasonTicketValid ( String  ticketId );
     public   boolean  isSeasonTicketInUse ( String  ticketId );
     public   void  recordSeasonTicketEntry ( String  ticketId );
     public   void  recordSeasonTicketExit ( String  ticketId );


}

src/bcccp/carpark/ICarparkObserver.java

src/bcccp/carpark/ICarparkObserver.java

package  bcccp . carpark ;

public   interface   ICarparkObserver   {
    
     public   void  notifyCarparkEvent ();
    

}

src/bcccp/carpark/ICarSensor.java

src/bcccp/carpark/ICarSensor.java

package  bcccp . carpark ;

public   interface   ICarSensor   {
     public   void  registerResponder ( ICarSensorResponder  responder );
     public   void  deregisterResponder ( ICarSensorResponder  responder );
    
     public   String  getId ();
     public   boolean  carIsDetected ();

}

src/bcccp/carpark/ICarSensorResponder.java

src/bcccp/carpark/ICarSensorResponder.java

package  bcccp . carpark ;

public   interface   ICarSensorResponder   {
    
     public   void  carEventDetected ( String  detectorId ,   boolean  detected );

}

src/bcccp/carpark/IGate.java

src/bcccp/carpark/IGate.java

package  bcccp . carpark ;

public   interface   IGate   {
     public   void  raise ();
     public   void  lower ();
    
     public   boolean  isRaised ();
    
}

src/bcccp/carpark/paystation/IPaystationController.java

src/bcccp/carpark/paystation/IPaystationController.java

package  bcccp . carpark . paystation ;

public   interface   IPaystationController   {
    
     public   void  ticketInserted ( String  barcode );
     public   void  ticketPaid ();
     public   void  ticketTaken ();

}

src/bcccp/carpark/paystation/IPaystationUI.java

src/bcccp/carpark/paystation/IPaystationUI.java

package  bcccp . carpark . paystation ;

public   interface   IPaystationUI   {
     public   void  registerController ( IPaystationController  controller );
     public   void  deregisterController ();
    
     public   void  printTicket ( String  carparkId ,   int  ticketNo ,   long  entryTime ,   long  paidTime ,   float  charge ,   String  barcode );
     public   void  display ( String  message );
     public   void  beep ();

}

src/bcccp/carpark/paystation/PaystationController.java

src/bcccp/carpark/paystation/PaystationController.java

package  bcccp . carpark . paystation ;

import  bcccp . carpark . ICarpark ;
import  bcccp . tickets . adhoc . IAdhocTicket ;

public   class   PaystationController  
         implements   IPaystationController   {
    
     private  enum STATE  {  IDLE ,  WAITING ,  REJECTED ,  PAID  }  
    
     private  STATE state_ ;
    
     private   IPaystationUI  ui_ ;
    
     private   ICarpark  carpark_ ;

     private   IAdhocTicket   adhocTicket_  =   null ;
     private   float  charge_ ;
    
    

     public   PaystationController ( ICarpark  carpark ,   IPaystationUI  ui )   {
        
         this . carpark_  =  carpark ;
         this . ui_  =  ui ;
        
        ui . registerController ( this );         
        setState ( STATE . IDLE );        
     }

    
    
     private   void  log ( String  message )   {
         System . out . println ( "EntryController : "   +  message );
     }

    
    
     private   void  setState ( STATE newState )   {
         switch   ( newState )   {
        
         case  IDLE :  
            state_  =  STATE . IDLE ;
            ui_ . display ( "Idle" );
            
            log ( "setState: IDLE" );
             break ;
            
         case  WAITING :  
            state_  =  STATE . WAITING ;
            log ( "setState: WAITING" );
             break ;
            
         case  REJECTED :  
            state_  =  STATE . WAITING ;
            log ( "setState: WAITING" );
             break ;
            
         case  PAID :  
            state_  =  STATE . PAID ;
            ui_ . display ( "Paid" );
            log ( "setState: PAID" );
             break ;           
            
         default :  
             break ;
            
         }            
     }

    
    
    @ Override
     public   void  ticketInserted ( String  barcode )   {
         if   ( state_  ==  STATE . IDLE )   {
            adhocTicket_  =  carpark_ . getAdhocTicket ( barcode );
             if   ( adhocTicket_  !=   null )   {
                charge_  =  carpark_ . calculateAddHocTicketCharge ( adhocTicket_ . getEntryDateTime ());
                ui_ . display ( "Pay "   +   String . format ( "%.2f" ,  charge_ ));
                setState ( STATE . WAITING );
             }
             else   {
                ui_ . beep ();
                ui_ . display ( "Take Rejected Ticket" );
                setState ( STATE . REJECTED );
                log ( "ticketInserted: ticket is not current" );                
             }
         }
         else   {
            ui_ . beep ();
            log ( "ticketInserted: called while in incorrect state" );              
         }
     }
    
    
    
    @ Override
     public   void  ticketPaid ()   {
         if   ( state_  ==  STATE . WAITING )   {
             long  payTime  =   System . currentTimeMillis ();
            
            adhocTicket_ . pay ( payTime ,  charge_ );
            
             String  carparkId  =  adhocTicket_ . getCarparkId ();
             int  ticketNo  =  adhocTicket_ . getTicketNo ();
             long  entryTime  =  adhocTicket_ . getEntryDateTime ();
             long  paidTime  =  adhocTicket_ . getPaidDateTime ();
             float  charge  =  adhocTicket_ . getCharge ();
             String  barcode  =  adhocTicket_ . getBarcode ();
            
            ui_ . printTicket ( carparkId ,  ticketNo ,  entryTime ,  paidTime ,  charge ,  barcode );
            setState ( STATE . PAID );
         }
         else   {
            ui_ . beep ();
            log ( "ticketPaid: called while in incorrect state" );              
         }
     }

    
    
    @ Override
     public   void  ticketTaken ()   {
         if   ( state_  ==  STATE . IDLE )   {
            ui_ . beep ();
            log ( "ticketTaken: called while in incorrect state" );                 
         }
         else   {
            setState ( STATE . IDLE );
         }
     }

}

src/bcccp/carpark/paystation/PaystationUI.java

src/bcccp/carpark/paystation/PaystationUI.java

package  bcccp . carpark . paystation ;

import  java . awt . EventQueue ;

import  javax . swing . JFrame ;
import  javax . swing . JPanel ;
import  javax . swing . border . EmptyBorder ;
import  javax . swing . border . TitledBorder ;

import  javax . swing . JTextField ;
import  java . awt . Font ;
import  java . awt . Toolkit ;

import  javax . swing . SwingConstants ;
import  javax . swing . JButton ;
import  java . awt . event . ActionListener ;
import  java . util . Date ;
import  java . awt . event . ActionEvent ;
import  javax . swing . JTextArea ;
import  java . awt . Color ;
import  javax . swing . UIManager ;

@ SuppressWarnings ( "serial" )
public   class   PaystationUI   extends   JFrame   implements   IPaystationUI   {

     private   JPanel  contentPane ;
     private   JTextField  displayTextField ;
     private   JTextField  barcodeTextField ;
     private   IPaystationController  controller ;
     private   JTextArea  ticketPrinterTextArea ;

    
    
     /**
     * Launch the application.
     */
     public   static   void  main ( String []  args )   {
         EventQueue . invokeLater ( new   Runnable ()   {
             public   void  run ()   {
                 try   {
                     PaystationUI  frame  =   new   PaystationUI ( 100 ,   100 );
                    frame . setVisible ( true );
                 }   catch   ( Exception  e )   {
                    e . printStackTrace ();
                 }
             }
         });
     }

    
    
     /**
     * Create the frame.
     */
     public   PaystationUI ( int  x ,   int  y )   {
        setTitle ( "PayStation UI" );
        setDefaultCloseOperation ( JFrame . EXIT_ON_CLOSE );
        setBounds ( x ,  y ,   350 ,   710 );
        contentPane  =   new   JPanel ();
        contentPane . setBorder ( new   EmptyBorder ( 5 ,   5 ,   5 ,   5 ));
        setContentPane ( contentPane );
        contentPane . setLayout ( null );
        
         JPanel  panel  =   new   JPanel ();
        panel . setBorder ( new   TitledBorder ( null ,   "LCD Display" ,   TitledBorder . LEADING ,   TitledBorder . TOP ,   null ,   null ));
        panel . setBounds ( 5 ,   5 ,   320 ,   106 );
        contentPane . add ( panel );
        panel . setLayout ( null );
        
        displayTextField  =   new   JTextField ();
        displayTextField . setHorizontalAlignment ( SwingConstants . CENTER );
         //displayTextField.setText("Push Button");
        displayTextField . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        displayTextField . setEditable ( false );
        displayTextField . setBounds ( 10 ,   15 ,   298 ,   82 );
        panel . add ( displayTextField );
        displayTextField . setColumns ( 10 );
        
         JButton  issueAdhocTicketButton  =   new   JButton ( "Pay" );
        issueAdhocTicketButton . addActionListener ( new   ActionListener ()   {
             public   void  actionPerformed ( ActionEvent  e )   {
                pay ();
             }

         });
        issueAdhocTicketButton . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        issueAdhocTicketButton . setBounds ( 25 ,   283 ,   287 ,   46 );
        contentPane . add ( issueAdhocTicketButton );
        
         JPanel  panel_1  =   new   JPanel ();
        panel_1 . setBorder ( new   TitledBorder ( UIManager . getBorder ( "TitledBorder.border" ),   "Ticket Reader" ,   TitledBorder . LEADING ,   TitledBorder . TOP ,   null ,   new   Color ( 0 ,   0 ,   0 )));
        panel_1 . setBounds ( 15 ,   122 ,   310 ,   153 );
        contentPane . add ( panel_1 );
        panel_1 . setLayout ( null );
        
        barcodeTextField  =   new   JTextField ();
        barcodeTextField . setHorizontalAlignment ( SwingConstants . CENTER );
        barcodeTextField . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        barcodeTextField . setBounds ( 10 ,   21 ,   285 ,   53 );
        panel_1 . add ( barcodeTextField );
        barcodeTextField . setColumns ( 10 );
        
         JButton  btnNewButton  =   new   JButton ( "Read Ticket" );
        btnNewButton . addActionListener ( new   ActionListener ()   {
             public   void  actionPerformed ( ActionEvent  arg0 )   {
                ticketInserted ();
             }
         });
        btnNewButton . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        btnNewButton . setBounds ( 10 ,   85 ,   285 ,   45 );
        panel_1 . add ( btnNewButton );
        
         JPanel  panel_2  =   new   JPanel ();
        panel_2 . setBorder ( new   TitledBorder ( UIManager . getBorder ( "TitledBorder.border" ),   "Paystation Ticket Printer" ,   TitledBorder . LEADING ,   TitledBorder . TOP ,   null ,   new   Color ( 0 ,   0 ,   0 )));
        panel_2 . setBounds ( 5 ,   340 ,   320 ,   321 );
        contentPane . add ( panel_2 );
        panel_2 . setLayout ( null );
        
        ticketPrinterTextArea  =   new   JTextArea ();
        ticketPrinterTextArea . setBackground ( Color . LIGHT_GRAY );
        ticketPrinterTextArea . setText ( "" );
        ticketPrinterTextArea . setRows ( 10 );
        ticketPrinterTextArea . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   14 ));
        ticketPrinterTextArea . setEditable ( false );
        ticketPrinterTextArea . setBounds ( 10 ,   22 ,   295 ,   230 );
        panel_2 . add ( ticketPrinterTextArea );
        
         JButton  btnNewButton_1  =   new   JButton ( "Take Ticket" );
        btnNewButton_1 . addActionListener ( new   ActionListener ()   {
             public   void  actionPerformed ( ActionEvent  e )   {
                takeTicket ();
             }
         });
        btnNewButton_1 . setFont ( new   Font ( "Tahoma" ,   Font . PLAIN ,   24 ));
        btnNewButton_1 . setBounds ( 20 ,   263 ,   285 ,   45 );
        panel_2 . add ( btnNewButton_1 );
     }

    
    
    @ Override
     public   void  registerController ( IPaystationController  controller )   {
         this . controller  =  controller ;
     }

    
    
    @ Override
     public   void  deregisterController ()   {
         this . controller  =   null ;  
     }
    
    
    
     private   void  ticketInserted ()   {
         String  ticketStr  =  barcodeTextField . getText ();
        controller . ticketInserted ( ticketStr );    
     }
    
    
    
    @ Override
     public   void  display ( String  message )   {
        displayTextField . setText ( message );   
     }

    
    
    @ Override
     public   void  beep ()   {
         Toolkit . getDefaultToolkit (). beep ();  
     }
    
    
    
     private   void  pay ()   {
        log ( "pay : calling ticketPaid" );
        controller . ticketPaid ();     
     }

    
    
     private   void  takeTicket ()   {
        controller . ticketTaken ();
        ticketPrinterTextArea . setText ( "" );
        barcodeTextField . setText ( "" );
     }

    
    
     private   void  log ( String  message )   {
         System . out . println ( "EntryUI : "   +  message );
     }

    
    
    @ Override
     public   void  printTicket ( String  carparkId ,   int  tNo ,   long  entryTime ,   long  paidTime ,   float  charge ,   String  barcode )   {
         Date  entryDate  =   new   Date ( entryTime );
         Date  paidDate  =   new   Date ( paidTime );
         StringBuilder  builder  =   new   StringBuilder ();
        builder . append ( "Carpark    : "   +  carparkId  +   "\n" );
        builder . append ( "Ticket No  : "   +  tNo  +   "\n" );
        builder . append ( "Entry Time : "   +  entryDate  +   "\n" );
        builder . append ( "Paid  Time : "   +  paidDate  +   "\n" );
        builder . append ( "Charge     : "   +   String . format ( "%.2f" ,  charge )   +   "\n" );
        builder . append ( "Barcode    : "   +  barcode  +   "\n" );
        
        ticketPrinterTextArea . setText ( builder . toString ());           
     }

    
    
}

src/bcccp/Main.java

src/bcccp/Main.java

package  bcccp ;

import  java . awt . EventQueue ;

import  bcccp . carpark . CarSensor ;
import  bcccp . carpark . Carpark ;
import  bcccp . carpark . Gate ;
import  bcccp . carpark . entry . EntryController ;
import  bcccp . carpark . entry . EntryUI ;
import  bcccp . carpark . exit . ExitController ;
import  bcccp . carpark . exit . ExitUI ;
import  bcccp . carpark . paystation . PaystationController ;
import  bcccp . carpark . paystation . PaystationUI ;
import  bcccp . tickets . adhoc . AdhocTicketFactory ;
import  bcccp . tickets . adhoc . IAdhocTicket ;
import  bcccp . tickets . adhoc . AdhocTicketDAO ;
import  bcccp . tickets . adhoc . IAdhocTicketDAO ;
import  bcccp . tickets . season . ISeasonTicket ;
import  bcccp . tickets . season . ISeasonTicketDAO ;
import  bcccp . tickets . season . SeasonTicket ;
import  bcccp . tickets . season . SeasonTicketDAO ;
import  bcccp . tickets . season . UsageRecordFactory ;

public   class   Main   {

     public   static   void  main ( String []  args )   {
         EventQueue . invokeLater ( new   Runnable ()   {
             public   void  run ()   {
                 try   {
                     CarSensor  eos  =   new   CarSensor ( "Entry Outside Sensor" ,   20 ,   100 );
                     Gate  egate  =   new   Gate ( 20 ,   320 );
                     CarSensor  eis  =   new   CarSensor ( "Entry Inside Sensor" ,   20 ,   440 );
                     EntryUI  eui  =   new   EntryUI ( 320 ,   100 );     
                    
                     PaystationUI  pui  =   new   PaystationUI ( 660 ,   100 );
                    
                     ExitUI  xui  =   new   ExitUI ( 1000 ,   100 );  
                     CarSensor  xis  =   new   CarSensor ( "Exit Inside Sensor" ,   1330 ,   100 );
                     Gate  xgate  =   new   Gate ( 1330 ,   320 );
                     CarSensor  xos  =   new   CarSensor ( "Exit Outside Sensor" ,   1330 ,   440 );
                    
                     IAdhocTicketDAO  adhocTicketDAO  =   new   AdhocTicketDAO ( new   AdhocTicketFactory ());
                     ISeasonTicketDAO  seasonTicketDAO  =   new   SeasonTicketDAO ( new   UsageRecordFactory ());
                    
                     Carpark  carpark  =   new   Carpark ( "Bathurst Chase" ,   5 ,  adhocTicketDAO ,  seasonTicketDAO );
                    
                     ISeasonTicket  t1  =   new   SeasonTicket ( "S1111" , "Bathurst Chase" ,   0L ,   0L );
                     ISeasonTicket  t2  =   new   SeasonTicket ( "S2222" , "Bathurst Chase" ,   0L ,   0L );
                    
                    carpark . registerSeasonTicket ( t1 );
                    carpark . registerSeasonTicket ( t2 );
                    
                     //issue a ticket so that paystation can be tested
                    carpark . issueAdhocTicket ();
                    carpark . recordAdhocTicketEntry ();
                    carpark . recordSeasonTicketEntry ( t1 . getId ());
                    
                     IAdhocTicket  ticket  =  carpark . issueAdhocTicket ();
                    ticket . pay ( System . currentTimeMillis (),   5.0f );
                    
                    @ SuppressWarnings ( "unused" )
                     EntryController  entryController  =  
                             new   EntryController ( carpark ,  egate ,  eos ,  eis ,  eui );
                    
                    @ SuppressWarnings ( "unused" )
                     PaystationController  payController  =  
                             new   PaystationController ( carpark ,  pui );
                    
                    @ SuppressWarnings ( "unused" )
                     ExitController  exitController  =  
                     new   ExitController ( carpark ,  xgate ,  xis ,  xos ,  xui );
                    
                    eos . setVisible ( true );
                    egate . setVisible ( true );
                    eis . setVisible ( true );
                    eui . setVisible ( true );
                    
                    pui . setVisible ( true );
                    
                    xui . setVisible ( true );
                    xis . setVisible ( true );
                    xgate . setVisible ( true );
                    xos . setVisible ( true );
                    
                 }  
                 catch   ( Exception  e )   {
                    e . printStackTrace ();
                 }
             }
         });
     }

}

src/bcccp/tickets/adhoc/AdhocTicket.java

src/bcccp/tickets/adhoc/AdhocTicket.java

package  bcccp . tickets . adhoc ;

import  java . util . Date ;

public   class   AdhocTicket   implements   IAdhocTicket   {
    
     private   String  carparkId_ ;
     private   int  ticketNo_ ;
     private   long  entryDateTime ;
     private   long  paidDateTime ;
     private   long  exitDateTime ;
     private   float  charge ;
     private   String  barcode ;
     private  STATE state_ ;
    
     private  enum STATE  {  ISSUED ,  CURRENT ,  PAID ,  EXITED  }

    
    
     public   AdhocTicket ( String  carparkId ,   int  ticketNo ,   String  barcode )   {
         this . carparkId_  =  carparkId ;
         this . ticketNo_  =  ticketNo ;
         this . barcode  =  barcode ;
         this . state_  =  STATE . ISSUED ;      
     }

    
    
    @ Override
     public   String  getBarcode ()   {
         return  barcode ;
     }


    
    @ Override
     public   String  getCarparkId ()   {
         return  carparkId_ ;
     }

    
    
    @ Override
     public   int  getTicketNo ()   {
         return  ticketNo_ ;
     }
    

    
    @ Override
     public   void  enter ( long  entryDateTime )   {
         this . entryDateTime  =  entryDateTime ;
         this . state_  =  STATE . CURRENT ;         
     }
    
    
    
    @ Override
     public   long  getEntryDateTime ()   {
         return  entryDateTime ;
     }

    
    
    @ Override
     public   void  pay ( long  paidDateTime ,   float  charge )   {
         this . paidDateTime  =  paidDateTime ;
         this . charge  =  charge ;
        state_  =  STATE . PAID ;
     }
    
    
    
    @ Override
     public   long  getPaidDateTime ()   {
         return  paidDateTime ;
     }



    @ Override
     public   float  getCharge ()   {
         return  charge ;
     }

    
    
     public   String  toString ()   {
         Date  entryDate  =   new   Date ( entryDateTime );
         Date  paidDate  =   new   Date ( paidDateTime );
         Date  exitDate  =   new   Date ( exitDateTime );

         return   "Carpark    : "   +  carparkId_  +   "\n"   +
                "Ticket No  : "   +  ticketNo_  +   "\n"   +
                "Entry Time : "   +  entryDate  +   "\n"   +  
                "Paid Time  : "   +  paidDate  +   "\n"   +  
                "Exit Time  : "   +  exitDate  +   "\n"   +
                "State      : "   +  state_  +   "\n"   +
                "Barcode    : "   +  barcode ;        
     }



    @ Override
     public   boolean  isCurrent ()   {
         return  state_  ==  STATE . CURRENT ;
     }



    @ Override
     public   boolean  isPaid ()   {
         return  state_  ==  STATE . PAID ;
     }



    @ Override
     public   void  exit ( long  dateTime )   {
        exitDateTime  =  dateTime ;
        state_  =  STATE . EXITED ;
     }



    @ Override
     public   long  getExitDateTime ()   {
         return  exitDateTime ;
     }



    @ Override
     public   boolean  hasExited ()   {
         return  state_  ==  STATE . EXITED ;
     }


}

src/bcccp/tickets/adhoc/AdhocTicketDAO.java

src/bcccp/tickets/adhoc/AdhocTicketDAO.java

package  bcccp . tickets . adhoc ;

import  java . util . ArrayList ;
import  java . util . Collections ;
import  java . util . HashMap ;
import  java . util . List ;
import  java . util . Map ;

public   class   AdhocTicketDAO    implements   IAdhocTicketDAO    {

     private   Map < String ,   IAdhocTicket >  currentTickets ;
     private   IAdhocTicketFactory  adhocTicketFactory_ ;
     private   int  currentTicketNo ;

    
    
     public   AdhocTicketDAO ( IAdhocTicketFactory  adhocTicketFactory )   {
         this . adhocTicketFactory_  =  adhocTicketFactory ;
        currentTickets  =   new   HashMap <> ();        
     }

    
    
    @ Override
     public   IAdhocTicket  createTicket ( String  carparkId )   {
         IAdhocTicket  ticket  =  adhocTicketFactory_ . make ( carparkId ,   ++ currentTicketNo );
        currentTickets . put ( ticket . getBarcode (),  ticket );
         return  ticket ;   
     }
    
    
    
    @ Override
     public   IAdhocTicket  findTicketByBarcode ( String  barcode )   {
         return  currentTickets . get ( barcode );
     }    

    
    
    @ Override
     public   List < IAdhocTicket >  getCurrentTickets ()   {      
         return   Collections . unmodifiableList ( new   ArrayList < IAdhocTicket > ( currentTickets . values ()));
     }



}

src/bcccp/tickets/adhoc/AdhocTicketFactory.java

src/bcccp/tickets/adhoc/AdhocTicketFactory.java

package  bcccp . tickets . adhoc ;

public   class   AdhocTicketFactory   implements   IAdhocTicketFactory   {

    @ Override
     public   IAdhocTicket  make ( String  carparkId ,   int  ticketNo )   {
         String  barcode  =   "A"   +   Integer . toHexString ( ticketNo );
         return   new   AdhocTicket ( carparkId ,  ticketNo ,  barcode );
     }

}

src/bcccp/tickets/adhoc/IAdhocTicket.java

src/bcccp/tickets/adhoc/IAdhocTicket.java

package  bcccp . tickets . adhoc ;

public   interface   IAdhocTicket   {

     public   int  getTicketNo ();
     public   String  getBarcode ();
     public   String  getCarparkId ();

     public   void  enter ( long  dateTime );
     public   long  getEntryDateTime ();
     public   boolean  isCurrent ();
    
     public   void  pay ( long  dateTime ,   float  charge );
     public   long  getPaidDateTime ();
     public   boolean  isPaid ();
     public   float  getCharge ();
    
     public   void  exit ( long  dateTime );
     public   long  getExitDateTime ();
     public   boolean  hasExited ();
    
    
    
}

src/bcccp/tickets/adhoc/IAdhocTicketDAO.java

src/bcccp/tickets/adhoc/IAdhocTicketDAO.java

package  bcccp . tickets . adhoc ;

import  java . util . List ;

public   interface   IAdhocTicketDAO   {
    
     public   IAdhocTicket  createTicket ( String  carparkId );
     public   IAdhocTicket  findTicketByBarcode ( String  barcode );
     public   List < IAdhocTicket >  getCurrentTickets ();


}

src/bcccp/tickets/adhoc/IAdhocTicketFactory.java

src/bcccp/tickets/adhoc/IAdhocTicketFactory.java

package  bcccp . tickets . adhoc ;

public   interface   IAdhocTicketFactory   {
    
     public   IAdhocTicket  make ( String  carparkId ,   int  ticketNo );


}

src/bcccp/tickets/season/ISeasonTicket.java

src/bcccp/tickets/season/ISeasonTicket.java

package  bcccp . tickets . season ;

import  java . util . List ;

public   interface   ISeasonTicket   {
    
     public   String  getId ();
     public   String  getCarparkId ();
     public   long  getStartValidPeriod ();
     public   long  getEndValidPeriod ();
    
     public   boolean  inUse ();
     public   void  recordUsage ( IUsageRecord  record );
     public   IUsageRecord  getCurrentUsageRecord ();
     public   void  endUsage ( long  dateTime );
    
     public   List < IUsageRecord >  getUsageRecords ();

}

src/bcccp/tickets/season/ISeasonTicketDAO.java

src/bcccp/tickets/season/ISeasonTicketDAO.java

package  bcccp . tickets . season ;

public   interface   ISeasonTicketDAO   {
    
     public   void  registerTicket ( ISeasonTicket  ticket );
     public   void  deregisterTicket ( ISeasonTicket  ticket );
     public   int  getNumberOfTickets ();
    
     public   ISeasonTicket  findTicketById ( String  ticketId );
     public   void  recordTicketEntry ( String  ticketId  );
     public   void  recordTicketExit ( String  ticketId );
}

src/bcccp/tickets/season/IUsageRecord.java

src/bcccp/tickets/season/IUsageRecord.java

package  bcccp . tickets . season ;

public   interface   IUsageRecord   {
    
     public   void  finalise ( long  endDateTime );
     public   long  getStartTime ();
     public   long  getEndTime ();
     public   String  getSeasonTicketId ();

}

src/bcccp/tickets/season/IUsageRecordFactory.java

src/bcccp/tickets/season/IUsageRecordFactory.java

package  bcccp . tickets . season ;

public   interface   IUsageRecordFactory   {

     public   IUsageRecord  make ( String  ticketId ,   long  startDateTime );
}

src/bcccp/tickets/season/SeasonTicket.java

src/bcccp/tickets/season/SeasonTicket.java

package  bcccp . tickets . season ;

import  java . util . ArrayList ;
import  java . util . Collections ;
import  java . util . List ;

public   class   SeasonTicket   implements   ISeasonTicket   {
    
     private   List < IUsageRecord >  usages ;
     private   IUsageRecord  currentUsage  =   null ;
    
     private   String  ticketId ;
     private   String  carparkId ;
     private   long  startValidPeriod ;
     private   long  endValidPeriod ;
    
     public   SeasonTicket   ( String  ticketId ,   String  carparkId ,  
                          long  startValidPeriod ,
                          long  endValidPeriod )   {
         this . ticketId  =  ticketId ;
         this . carparkId  = carparkId ;
         this . startValidPeriod  =  startValidPeriod ;
         this . endValidPeriod  =  endValidPeriod ;
        
        usages  =   new   ArrayList < IUsageRecord > ();
     }


    @ Override
     public   String  getId ()   {
         return  ticketId ;
     }


    @ Override
     public   String  getCarparkId ()   {
         return  carparkId ;
     }


    @ Override
     public   long  getStartValidPeriod ()   {
         return  startValidPeriod ;
     }


    @ Override
     public   long  getEndValidPeriod ()   {
         return  endValidPeriod ;
     }


    @ Override
     public   boolean  inUse ()   {
         return  currentUsage  !=   null ;
     }


    @ Override
     public   void  recordUsage ( IUsageRecord  record )   {
        currentUsage  =  record ;
         if   ( ! usages . contains ( record )   )   {
            usages . add ( record );
         }
        
     }


    @ Override
     public   IUsageRecord  getCurrentUsageRecord ()   {
         return  currentUsage ;
     }


    @ Override
     public   List < IUsageRecord >  getUsageRecords ()   {
         return   Collections . unmodifiableList ( usages );
     }


    @ Override
     public   void  endUsage ( long  dateTime )   {
         if   ( currentUsage  ==   null )   throw   new   RuntimeException ( "SeasonTicket.endUsage : ticket is not in use" );
        
        currentUsage . finalise ( dateTime );
        currentUsage  =   null ;
        
     }


    
     public   String  toString ()   {
         StringBuilder  builder  =   new   StringBuilder ();
        builder . append ( "Carpark    : "   +  carparkId  +   "\n"   +
                "Ticket No  : "   +  ticketId  +   "\n"   );
         for   ( IUsageRecord  usage  :  usages )   {
            builder . append ( usage . toString ()   +   "\n" );
         }
         return  builder . toString ();
     }


}

src/bcccp/tickets/season/SeasonTicketDAO.java

src/bcccp/tickets/season/SeasonTicketDAO.java

package  bcccp . tickets . season ;

import  java . util . HashMap ;
import  java . util . Map ;

import  bcccp . tickets . season . ISeasonTicket ;
import  bcccp . tickets . season . IUsageRecordFactory ;

public   class   SeasonTicketDAO   implements   ISeasonTicketDAO   {

     private   Map < String ,   ISeasonTicket >  currentTickets ;
     private   IUsageRecordFactory  factory ;

    
    
     public   SeasonTicketDAO ( IUsageRecordFactory  factory )   {
         this . factory  =  factory ;
        currentTickets  =   new   HashMap <> ();        
     }
    
    
    
    @ Override
     public   void  registerTicket ( ISeasonTicket  ticket )   {
         if   ( ! currentTickets . containsKey ( ticket . getId ()))   {
            currentTickets . put ( ticket . getId (), ticket );
         }
     }
    
    
    
    @ Override
     public   void  deregisterTicket ( ISeasonTicket  ticket )   {
         if   ( currentTickets . containsKey ( ticket . getId ()))   {
            currentTickets . remove ( ticket . getId ());
         }
     }
        
        
    @ Override
     public   int  getNumberOfTickets ()   {
         return  currentTickets . size ();
     }

    @ Override
     public   ISeasonTicket  findTicketById ( String  barcode )   {
         if   ( currentTickets . containsKey ( barcode ))   {
             return  currentTickets . get ( barcode );
         }
         return   null ;
     }



    @ Override
     public   void  recordTicketEntry ( String  ticketId )   {
         ISeasonTicket  ticket  =  findTicketById ( ticketId );
         if   ( ticket  ==   null )   throw   new   RuntimeException ( "recordTicketUsage : no such ticket: "   +  ticketId );
        
         long  datetime  =   System . currentTimeMillis ();
         IUsageRecord  usage  =  factory . make ( ticketId ,  datetime );
        ticket . recordUsage ( usage );       
     }



    @ Override
     public   void  recordTicketExit ( String  ticketId )   {
         ISeasonTicket  ticket  =  findTicketById ( ticketId );
         if   ( ticket  ==   null )   throw   new   RuntimeException ( "finaliseTicketUsage : no such ticket: "   +  ticketId );

         long  dateTime  =   System . currentTimeMillis ();
        ticket . endUsage ( dateTime );
        
        
        
     }
}


src/bcccp/tickets/season/UsageRecord.java

src/bcccp/tickets/season/UsageRecord.java

package  bcccp . tickets . season ;

public   class   UsageRecord   implements   IUsageRecord   {
    
     String  ticketId ;
     long  startDateTime ;
     long  endDateTime ;
    
    
    
     public   UsageRecord ( String  ticketId ,   long  startDateTime )   {
         this . ticketId  =  ticketId ;
         this . startDateTime  =  startDateTime ;
     }
    
    
    
     public   void  finalise ( long  endDateTime )   {
         this . endDateTime  =  endDateTime ;
     }
    
    
    
    @ Override
     public   long  getStartTime ()   {
         return  startDateTime ;
     }



    @ Override
     public   long  getEndTime ()   {
         return  endDateTime ;
     }



    @ Override
     public   String  getSeasonTicketId ()   {
         return  ticketId ;
     }

    
    
     public   String  toString ()   {
         return   ( "Usage : startDateTime : "   +  startDateTime  +   ", endDateTime: "   +  endDateTime );
     }




}

src/bcccp/tickets/season/UsageRecordFactory.java

src/bcccp/tickets/season/UsageRecordFactory.java

package  bcccp . tickets . season ;

public   class   UsageRecordFactory   implements   IUsageRecordFactory   {

    @ Override
     public   IUsageRecord  make ( String  ticketId ,   long  startDateTime )   {
         return   new   UsageRecord ( ticketId ,  startDateTime );
     }

}