class Participant {
  Status{
    NotAssigned {
      assign(Guide aGuide8)[isGuideAvailable()]
        / {
        doAssignGuide(aGuide); 
      }-> Assigned;
      
      // 100% refund
      cancel()
        /{
        doRefund(0);
      } -> Cancelled;
      
      start()[isTime()]
        / {
        doRefund(0); 
      } -> Cancelled;
      
      start() -> NotAssigned;
      
      pay() -> NotAssigned;
    }
	// Same as NotPaid
    Assigned{
      pay()[!hasAuthCode()]
        / {
        rejectPayment();
      }  -> Assigned;
      
      pay()[hasAuthCode()]
         -> Paid;
      
      start()
        / {
        doRefund(0)
        }
      -> Cancelled;
    }
    
    Paid {
      // start tour, and it's time to go
      start()[isTime()]
        /{
        // doStartTour();
      } -> Started;
      
      // start tour, but not time to start yet
      start()[!isTime()]
        -> Paid;
      
      // 50% refund
      cancel() /{
        doRefund(50);
      } -> Cancelled;
      
      pay() -> Paid;
    }
    
    Started {
      finish() -> Finished;
      
      // 10% refund
      cancel() 
        /{
        doRefund(10);
      }-> Cancelled;
		
      pay() -> Started;
    }
    
    Finished {
      start() -> Finished;
      pay() -> Finished;
    }
    
    Cancelled {
      pay() -> Cancelled;
    }
  }

  private void doAssignGuide(Guide aGuide){
    getTour().setGuide(aGuide);
  }
  
  private boolean isGuideAvailable() {
    Guide g = getTour().getGuide();
    return g != null || !g.isEmpty();
  }

  private void rejectAssignGuide(String error){
    throw new RuntimeException(error);
  }

  private void rejectPayment(){
    throw new RuntimeException("Payment not accepted");
  }

  private void doRefund(Integer refundedPercentage) {
  setRefundedPercentageAmount(refundedPercentage);
    }
  
  private boolean hasAuthCode() {
    return getAuthorizationCode() != null && !getAuthorizationCode().isEmpty();
  }

  private boolean isTime() {
    java.util.Date today = new java.util.Date();
    // timeDifference = today - getSnowShoeTour().getStartDate() (using getTime --> in ms)
    long timeDifference = today.getTime() - getSnowShoeTour().getStartDate().getTime();
    // convert ms to weeks
    int weekDifference = (int) timeDifference / (1000*60*60*24*7);

    // isTime = (weekDifference == getTour().getStartWeek())
    return weekDifference == getTour().getStartWeek();
  }
}

