class TradingWeekImpl extends JodaWorkingWeek implements TradingWeek {

    @Override
    public DateTime getPreviousSessionDate(DateTime dt, Period period) {
        if(dt == null) {
            return null;
        }
        int interval = period.size();
        PeriodType periodType = period.getPeriodType();
        dt = dt.millisOfSecond().withMinimumValue();
        TradingSession tradingSession = getTradingSessionOnOrBefore(dt);
        boolean skip = false;
        switch(periodType) {
            case YEAR: {
                dt = dt.minusYears(interval).monthOfYear().withMaximumValue();
                dt = dt.dayOfMonth().withMaximumValue();
                skip = true;
            }
            case QUARTER: {
                if(!skip) {
                	LocalTime lt = dt.toLocalTime();
                    dt = ExtendedChronology.withPeriodEnd(dt).minusMonths(3 * interval).dayOfMonth().withMaximumValue();
                    dt = dt.withHourOfDay(lt.getHourOfDay()).withMinuteOfHour(lt.getMinuteOfHour()).
                    	withSecondOfMinute(lt.getSecondOfMinute());
                    skip = true;
                }
            }
            case MONTH: {
                if(!skip) {
                	dt = dt.minusMonths(interval);
                    dt = dt.dayOfMonth().withMaximumValue();
                    skip = true;
                }
            }
            case WEEK: {
                if(!skip) {
                	dt = dt.minusWeeks(interval);
                    dt = dt.withDayOfWeek(getEndSession().day());
                    skip = true;
                }
            }
            case DAY: {
                if(periodType != PeriodType.WEEK) {
                    dt = skip ? dt :  dt.minusDays(interval);
                    tradingSession = getTradingSessionOnOrBefore(dt);
                    if(tradingSession.day() > dt.getDayOfWeek()) {
                        dt = dt.minusDays((DateTimeConstants.SUNDAY - dt.getDayOfWeek()) + 1);
                    }
                    dt = dt.withDayOfWeek(tradingSession.day());
                    skip = true;
                }
            }
            case HOUR: {
                if(skip) {
                    LocalTime lt = tradingSession.end();
                    dt = dt.withHourOfDay(lt.getHourOfDay());
                }else{
                    dt = dt.minusHours(interval);
                    tradingSession = getTradingSessionOnOrBefore(dt);
                    if(!tradingSession.contains(dt)) {
                        if(tradingSession.day() > dt.getDayOfWeek()) {
                            dt = dt.minusDays((DateTimeConstants.SUNDAY - dt.getDayOfWeek()) + 1);
                        }
                        dt = dt.withDayOfWeek(tradingSession.day());
                        dt = dt.withHourOfDay(tradingSession.end().getHourOfDay());
                    }
                    skip = true;
                }
            }
            case MINUTE: {
                if(skip) {
                    LocalTime lt = tradingSession.end();
                    dt = dt.withMinuteOfHour(lt.getMinuteOfHour());
                }else{
                    dt = dt.minusMinutes(interval);
                    tradingSession = getTradingSessionOnOrBefore(dt);
                    if(!tradingSession.contains(dt)) {
                        if(tradingSession.day() > dt.getDayOfWeek()) {
                            dt = dt.minusDays((DateTimeConstants.SUNDAY - dt.getDayOfWeek()) + 1);
                        }
                        dt = dt.withDayOfWeek(tradingSession.day());
                        LocalTime lt = tradingSession.end();
                        dt = dt.withHourOfDay(lt.getHourOfDay()).withMinuteOfHour(lt.getMinuteOfHour());
                    }
                    skip = true;
                }
            }
            case SECOND: {
                if(skip) {
                    dt = dt.withSecondOfMinute(0);
                }else{
                    dt = dt.minusSeconds(interval);
                    tradingSession = getTradingSessionOnOrBefore(dt);
                    if(!tradingSession.contains(dt)) {
                        if(tradingSession.day() > dt.getDayOfWeek()) {
                            dt = dt.plusDays((DateTimeConstants.SUNDAY - dt.getDayOfWeek()) + 1);
                        }
                        dt = dt.withDayOfWeek(tradingSession.day());
                        LocalTime lt = tradingSession.end();
                        dt = dt.withHourOfDay(lt.getHourOfDay()).withMinuteOfHour(lt.getMinuteOfHour());
                        dt = dt.withSecondOfMinute(0);
                    }
                }
                
                // Guarantee new date is aligned to a business date.
                calculator.setStartDate(dt.toLocalDate());
                LocalDate ldt = calculator.getCurrentBusinessDate();
                if(!ldt.isEqual(dt.toLocalDate())) {
                    tradingSession = getTradingSessionOnOrBefore(ldt.toDateTime(dt.toLocalTime()));
                    if(tradingSession.day() > dt.getDayOfWeek()) {
                        dt = dt.minusDays((DateTimeConstants.SUNDAY - dt.getDayOfWeek()) + 1);
                    }
                    dt = dt.withDayOfWeek(tradingSession.day());
                    LocalTime lt = tradingSession.end();
                    dt = dt.withHourOfDay(lt.getHourOfDay()).withMinuteOfHour(lt.getMinuteOfHour()).withSecondOfMinute(0);
                }
                break;
            }
            case TICK: {
                if(!tradingSession.contains(dt)) {
                    tradingSession = getTradingSessionOnOrBefore(dt);
                    if(tradingSession.day() > dt.getDayOfWeek()) {
                        dt = dt.plusDays((DateTimeConstants.SUNDAY - dt.getDayOfWeek()) + 1);
                    }
                    dt = dt.withDayOfWeek(tradingSession.day());
                    LocalTime lt = tradingSession.end();
                    dt = dt.withHourOfDay(lt.getHourOfDay()).withMinuteOfHour(lt.getMinuteOfHour());
                    dt = dt.withSecondOfMinute(lt.getSecondOfMinute()).withMillisOfSecond(0);
                }
            }
            
            
        }
        return dt;
    }

    private  TradingWeekImpl(byte tradingDays);

}