diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..169393442 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,55 @@ +# 지하철 노선도 미션 +- 지하철 역과 노선을 관리하는 지하철 노선도 기능을 구현한다. + +## 구현할 기능 목록 + +### 초기 설정 +- 프로그램 시작 시 역, 노선 등 필요한 정보를 미리 세팅하기 +> 아래의 사전 등록 정보로 초기 설정하기 +``` + 1. 지하철역으로 교대역, 강남역, 역삼역, 남부터미널역, 양재역, 양재시민의숲역, 매봉역이 등록되어 있다. + 2. 지하철 노선으로 2호선, 3호선, 신분당선이 등록되어 있다. + 3. 노선에 역이 아래와 같이 등록되어 있다.(왼쪽 끝이 상행 종점) + - 2호선: 교대역 - 강남역 - 역삼역 + - 3호선: 교대역 - 남부터미널역 - 양재역 - 매봉역 + - 신분당선: 강남역 - 양재역 - 양재시민의숲역 + ``` + +### 지하철 역 관련 기능 +- 지하철 역 등록 + - 예외: 지하철 역 이름은 2글자 이상이어야 한다. + - 예외: 지하철 역 이름은 중복될 수 없다. +- 지하철 역 삭제 + - 예외: 노선에 등록되어 있는 역은 삭제할 수 없다. +- 지하철 역 목록 조회 + +###지하철 노선 관련 기능 +- 지하철 노선 등록 + - 예외: 지하철 노선 이름은 중복될 수 없다. + - 예외: 지하철 노선 이름은 2글자 이상이어야 한다. +

+ 노선 등록 시 상행 종점역과 하행 종점역을 입력받아야 한다. + - 예외: 등록되어 있지 않은 역이 상,하행 종점역 입력으로 들어왔을 때 + +- 지하철 노선 삭제 + - 예외: 존재하지 않는 노선을 삭제하려는 경우 + +- 지하철 노선 목록 조회 + +###지하철 구간 추가 기능 +- 노선에 새로운 역을 등록하는 기능 + - 역과 역 사이: 구간 + - 구간들의 모음: 노선 + - 예외: 이미 노선에 등록되어있는 역이 입력으로 들어오는 경우 + +###지하철 구간 삭제 기능 +- 노선에 등록된 역을 제거하는 기능 + - 상행 종점 제거 시 다음 역이 상행 종점 + - 하행 종점 제거 시 이전 역이 하행 종점 + - 예외: 노선에 포함된 역이 두 개 이하인 노선의 역을 제거하려는 경우 + +###지하철 노선에 등록된 역 조회 기능 +- 노선의 상행 종점부터 하행 종점까지 연결된 순서대로 역 목록을 조회한다. + +###지하철 노선도 출력 기능 + diff --git a/src/main/java/subway/Application.java b/src/main/java/subway/Application.java index 0bcf786cc..f2fe66546 100644 --- a/src/main/java/subway/Application.java +++ b/src/main/java/subway/Application.java @@ -1,10 +1,14 @@ package subway; +import subway.controller.SubwayMapEditor; + import java.util.Scanner; public class Application { public static void main(String[] args) { final Scanner scanner = new Scanner(System.in); // TODO: 프로그램 구현 + SubwayMapEditor subwayMapEditor = new SubwayMapEditor(scanner); + subwayMapEditor.run(); } } diff --git a/src/main/java/subway/controller/SubwayMapEditor.java b/src/main/java/subway/controller/SubwayMapEditor.java new file mode 100644 index 000000000..c5a89769c --- /dev/null +++ b/src/main/java/subway/controller/SubwayMapEditor.java @@ -0,0 +1,24 @@ +package subway.controller; + +import subway.domain.SubwayMap; +import subway.view.MainScreenInputView; +import subway.view.MainScreenOutputView; + +import java.util.Scanner; + +public class SubwayMapEditor { + private final Scanner scanner; + + public SubwayMapEditor(Scanner scanner) { + this.scanner = scanner; + } + + public void run() { + SubwayMap subwayMap = new SubwayMap(); + boolean isPersist = false; + do { + isPersist = MainScreenInputView.getMainScreenUserSelection(scanner); + } while (isPersist); + + } +} diff --git a/src/main/java/subway/domain/Line.java b/src/main/java/subway/domain/Line.java index f4d738d5a..f1a9eac53 100644 --- a/src/main/java/subway/domain/Line.java +++ b/src/main/java/subway/domain/Line.java @@ -1,15 +1,59 @@ package subway.domain; +import java.util.ArrayList; +import java.util.List; + public class Line { + private static final String INFO = "[INFO] "; + private static final String STATION_NUMBER_MESSAGE = "[ERROR] 노선의 역 개수가 2개 이하이므로 삭제할 수 없습니다."; + private String name; + private List stationsOnLine = new ArrayList<>(); public Line(String name) { this.name = name; } + public void registerStation(Station station) { + stationsOnLine.add(station); + } + + public boolean isStationRegistered(String stationName) { + for (Station station : stationsOnLine) { + if (station.getName().equals(stationName)) { + return true; + } + } + return false; + } + + public void printStations() { + for (Station station : stationsOnLine) { + System.out.println(INFO + station.getName()); + } + System.out.println(); + } + public String getName() { return name; } - // 추가 기능 구현 + public boolean isSameName(String lineName) { + return this.name.equals(lineName); + } + + public int getSize() { + return stationsOnLine.size(); + } + + public void insert(Station station, int order) { + stationsOnLine.add(order-1, station); + } + + public void remove(String stationName) { + if (stationsOnLine.size() <= 2) { + throw new IllegalArgumentException(STATION_NUMBER_MESSAGE); + } + stationsOnLine.remove(new Station(stationName)); + } } diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/LineRepository.java index 49132ddb6..3d4062767 100644 --- a/src/main/java/subway/domain/LineRepository.java +++ b/src/main/java/subway/domain/LineRepository.java @@ -6,6 +6,12 @@ import java.util.Objects; public class LineRepository { + private static final String INFO = "[INFO] "; + private static final String INFO_WITH_BORDER = "[INFO] ---"; + private static final String LINE_LIST = "## 노선 목록"; + private static final String SUBWAY_MAP = "## 지하철 노선도"; + private static final String LINE_NOT_EXIST = "[ERROR] 존재하지 않는 노선입니다."; + private static final List lines = new ArrayList<>(); public static List lines() { @@ -19,4 +25,33 @@ public static void addLine(Line line) { public static boolean deleteLineByName(String name) { return lines.removeIf(line -> Objects.equals(line.getName(), name)); } + + public static void isLineExist(String lineName) { + boolean flag = false; + for (Line line : lines) { + flag = line.getName().equals(lineName); + if(flag) break; + } + if (!flag) { + throw new IllegalArgumentException(LINE_NOT_EXIST); + } + } + + public static void printLines() { + System.out.println(LINE_LIST); + for (Line line : lines) { + System.out.println(INFO + line.getName()); + } + System.out.println(); + } + + public static void printMap() { + System.out.println(); + System.out.println(SUBWAY_MAP); + for (Line line : lines) { + System.out.println(INFO + line.getName()); + System.out.println(INFO_WITH_BORDER); + line.printStations(); + } + } } diff --git a/src/main/java/subway/domain/Station.java b/src/main/java/subway/domain/Station.java index bdb142590..010c9533b 100644 --- a/src/main/java/subway/domain/Station.java +++ b/src/main/java/subway/domain/Station.java @@ -1,9 +1,12 @@ package subway.domain; +import java.util.Objects; + public class Station { private String name; public Station(String name) { + // TODO 이름 2글자 이상인지 확인할 것 this.name = name; } @@ -11,5 +14,20 @@ public String getName() { return name; } - // 추가 기능 구현 + public boolean isSameName(String stationName) { + return this.name.equals(stationName); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Station station = (Station) o; + return Objects.equals(name, station.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } } diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/StationRepository.java index b7245c0f3..16169f5a9 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/StationRepository.java @@ -6,6 +6,9 @@ import java.util.Objects; public class StationRepository { + private static final String INFO = "[INFO] "; + private static final String STATION_LIST = "## 역 목록"; + private static final List stations = new ArrayList<>(); public static List stations() { @@ -19,4 +22,21 @@ public static void addStation(Station station) { public static boolean deleteStation(String name) { return stations.removeIf(station -> Objects.equals(station.getName(), name)); } + + public static boolean isStationExist(String stationName) { + for (Station station : stations) { + if (station.isSameName(stationName)) { + return true; + } + } + return false; + } + + public static void printStations() { + System.out.println(); + System.out.println(STATION_LIST); + for (Station station : stations) { + System.out.println(INFO + station.getName()); + } + } } diff --git a/src/main/java/subway/domain/SubwayMap.java b/src/main/java/subway/domain/SubwayMap.java new file mode 100644 index 000000000..56f84a456 --- /dev/null +++ b/src/main/java/subway/domain/SubwayMap.java @@ -0,0 +1,75 @@ +package subway.domain; + +public class SubwayMap { + private static final String LINE_NUMBER_TWO = "2호선"; + private static final String LINE_NUMBER_THREE = "3호선"; + private static final String LINE_NEW_BOONDANG = "신분당선"; + private static final String GYODAE_STATION = "교대역"; + private static final String GANGNAM_STATION = "강남역"; + private static final String YEOKSAM_STATION = "역삼역"; + private static final String NAMBU_TERMINAL_STATION = "남부터미널역"; + private static final String YANGJAE_STATION = "양재역"; + private static final String YANGJAE_CITIZEN_FOREST_STATION = "양재시민의숲역"; + private static final String MAEBONG_STATION = "매봉역"; + + private Line lineNumberTwo; + private Line lineNumberThree; + private Line lineNewBoondang; + private Station gyodaeStation; + private Station gangnamStation; + private Station yeoksamStation; + private Station nambuTerminalStation; + private Station yangjaeStation; + private Station yangjaeCitizenForestStation; + private Station maebongStation; + + public SubwayMap() { + initialize(); + } + + public void initialize() { + initializeLine(); + initializeStation(); + initializeMap(); + } + + private void initializeLine() { + lineNumberTwo = new Line(LINE_NUMBER_TWO); + lineNumberThree = new Line(LINE_NUMBER_THREE); + lineNewBoondang = new Line(LINE_NEW_BOONDANG); + LineRepository.addLine(lineNumberTwo); + LineRepository.addLine(lineNumberThree); + LineRepository.addLine(lineNewBoondang); + } + + private void initializeStation() { + gyodaeStation = new Station(GYODAE_STATION); + gangnamStation = new Station(GANGNAM_STATION); + yeoksamStation = new Station(YEOKSAM_STATION); + nambuTerminalStation = new Station(NAMBU_TERMINAL_STATION); + yangjaeStation = new Station(YANGJAE_STATION); + yangjaeCitizenForestStation = new Station(YANGJAE_CITIZEN_FOREST_STATION); + maebongStation = new Station(MAEBONG_STATION); + StationRepository.addStation(gyodaeStation); + StationRepository.addStation(gangnamStation); + StationRepository.addStation(yeoksamStation); + StationRepository.addStation(nambuTerminalStation); + StationRepository.addStation(yangjaeStation); + StationRepository.addStation(yangjaeCitizenForestStation); + StationRepository.addStation(maebongStation); + } + + private void initializeMap() { + lineNumberTwo.registerStation(gyodaeStation); + lineNumberTwo.registerStation(gangnamStation); + lineNumberTwo.registerStation(yeoksamStation); + lineNumberThree.registerStation(gyodaeStation); + lineNumberThree.registerStation(nambuTerminalStation); + lineNumberThree.registerStation(yangjaeStation); + lineNumberThree.registerStation(maebongStation); + lineNewBoondang.registerStation(gangnamStation); + lineNewBoondang.registerStation(yangjaeStation); + lineNewBoondang.registerStation(yangjaeCitizenForestStation); + } + +} diff --git a/src/main/java/subway/type/LineScreenFunctionType.java b/src/main/java/subway/type/LineScreenFunctionType.java new file mode 100644 index 000000000..e0cc9c1ac --- /dev/null +++ b/src/main/java/subway/type/LineScreenFunctionType.java @@ -0,0 +1,37 @@ +package subway.type; + +import subway.domain.LineRepository; +import subway.view.LineInputView; + +public enum LineScreenFunctionType { + REGISTER_STATION(1) { + @Override + public void execute() { + LineInputView.registerLine(); + } + }, + REMOVE_STATION(2) { + @Override + public void execute() { + LineInputView.removeLine(); + } + }, + PRINT_STATION(3) { + @Override + public void execute() { + LineRepository.printLines(); + } + }; + + private final int functionCode; + + LineScreenFunctionType(int functionCode) { + this.functionCode = functionCode; + } + + public boolean isSameFunctionCode(int number) { + return this.functionCode == number; + } + + public abstract void execute(); +} diff --git a/src/main/java/subway/type/MainScreenFunctionType.java b/src/main/java/subway/type/MainScreenFunctionType.java new file mode 100644 index 000000000..706bdea7b --- /dev/null +++ b/src/main/java/subway/type/MainScreenFunctionType.java @@ -0,0 +1,46 @@ +package subway.type; + +import subway.domain.LineRepository; +import subway.view.LineInputView; +import subway.view.SectionInputView; +import subway.view.SectionOutputView; +import subway.view.StationInputView; + +public enum MainScreenFunctionType { + MANAGE_STATION(1) { + @Override + public void execute() { + StationInputView.getStationScreenUserSelection(); + } + }, + MANAGE_LINE(2) { + @Override + public void execute() { + LineInputView.getLineScreenUserSelection(); + } + }, + MANAGE_SECTION(3) { + @Override + public void execute() { + SectionInputView.getSectionScreenUserSelection(); + } + }, + PRINT_MAP(4) { + @Override // TODO 지하철 노선도 출력 + public void execute() { + LineRepository.printMap(); + } + }; + + private final int functionCode; + + MainScreenFunctionType(int functionCode) { + this.functionCode = functionCode; + } + + public boolean isSameFunctionCode(int number) { + return this.functionCode == number; + } + + public abstract void execute(); +} diff --git a/src/main/java/subway/type/SectionScreenFunctionType.java b/src/main/java/subway/type/SectionScreenFunctionType.java new file mode 100644 index 000000000..d1690ebdf --- /dev/null +++ b/src/main/java/subway/type/SectionScreenFunctionType.java @@ -0,0 +1,31 @@ +package subway.type; + +import subway.view.LineInputView; +import subway.view.SectionInputView; + +public enum SectionScreenFunctionType { + REGISTER_SECTION(1) { + @Override + public void execute() { + SectionInputView.registerSection(); + } + }, + REMOVE_SECTION(2) { + @Override + public void execute() { + SectionInputView.removeSection(); + } + }; + + private final int functionCode; + + SectionScreenFunctionType(int functionCode) { + this.functionCode = functionCode; + } + + public boolean isSameFunctionCode(int number) { + return this.functionCode == number; + } + + public abstract void execute(); +} diff --git a/src/main/java/subway/type/StationScreenFunctionType.java b/src/main/java/subway/type/StationScreenFunctionType.java new file mode 100644 index 000000000..901d6033f --- /dev/null +++ b/src/main/java/subway/type/StationScreenFunctionType.java @@ -0,0 +1,38 @@ +package subway.type; + +import subway.view.StationInputView; + +import static subway.domain.StationRepository.printStations; + +public enum StationScreenFunctionType { + REGISTER_STATION(1) { + @Override + public void execute() { + StationInputView.registerStation(); + } + }, + REMOVE_STATION(2) { + @Override + public void execute() { + StationInputView.removeStation(); + } + }, + PRINT_STATION(3) { + @Override + public void execute() { + printStations(); + } + }; + + private final int functionCode; + + StationScreenFunctionType(int functionCode) { + this.functionCode = functionCode; + } + + public boolean isSameFunctionCode(int number) { + return this.functionCode == number; + } + + public abstract void execute(); +} diff --git a/src/main/java/subway/view/LineInputView.java b/src/main/java/subway/view/LineInputView.java new file mode 100644 index 000000000..39bdef258 --- /dev/null +++ b/src/main/java/subway/view/LineInputView.java @@ -0,0 +1,213 @@ +package subway.view; + +import subway.domain.Line; +import subway.domain.LineRepository; +import subway.domain.Station; +import subway.domain.StationRepository; +import subway.type.LineScreenFunctionType; + +import java.util.Scanner; + +public class LineInputView { + private static final String SELECT_MESSAGE = "## 원하는 기능을 선택하세요."; + private static final String CANNOT_SELECT_MESSAGE = "[ERROR] 선택할 수 없는 기능입니다."; + private static final String REGISTER_LINE_MESSAGE = "## 등록할 노선 이름을 입력하세요."; + private static final String REGISTER_COMPLETE_MESSAGE = "[INFO] 지하철 노선이 등록되었습니다."; + private static final String REMOVE_LINE_MESSAGE = "## 삭제할 노선 이름을 입력하세요."; + private static final char LINE_NAME_ENDED_WITH = '선'; + private static final String LINE_NAME_LENGTH_MESSAGE = "[ERROR] 노선 이름은 두 글자 이상이어야 합니다."; + private static final String LINE_NAME_INCLUDE_NOT_KOREAN_MESSAGE = "[ERROR] 노선 이름은 한글이어야 합니다."; + private static final String LINE_NAME_SHOULD_BE_ENDED_WITH_LINE_MESSAGE = "[ERROR] 노선 이름 맨 뒤에 '선'을 붙여주세요."; + private static final String LINE_NAME_INCLUDE_NUMBER_MESSAGE = "[ERROR] 노선 이름에 숫자를 포함하면 안 됩니다."; + private static final String LINE_NAME_INCLUDE_SPACE_MESSAGE = "[ERROR] 노선 이름에 공백을 포함하면 안 됩니다."; + private static final String LINE_NAME_HAS_DUPLICATION_MESSAGE = "[ERROR] 이미 등록되어 있는 노선입니다."; + private static final char ONE = '1'; + private static final int INTEGER_ONE = 1; + private static final char MINIMUM_LINE_NAME_LENGTH = 2; + private static final char THREE = '3'; + private static final char BACK = 'B'; + private static final String SPACE = " "; + private static final int FIRST_CHARACTER = 0; + private static final String KOREAN_REGULAR_EXPRESSION = "^[가-힣]*$"; + private static final String HAS_NUMBER_REGULAR_EXPRESSION = ".*[0-9].*"; + + private static final Scanner scanner = new Scanner(System.in); + + private LineInputView() { + + } + + public static void getLineScreenUserSelection() { + LineOutputView.printManageLineScreen(); + System.out.println(SELECT_MESSAGE); + String userInput = scanner.nextLine(); + try { + validateUserInput(userInput); + if (isUserInputBack(userInput.charAt(FIRST_CHARACTER))) { + MainScreenInputView.getMainScreenUserSelection(scanner); + return; + } + executeFunction(userInput); + } catch (Exception e) { + System.out.println(); + System.out.println(e.getMessage()); + getLineScreenUserSelection(); + } + } + + private static void executeFunction(String userInput) { + for (LineScreenFunctionType lineScreenFunctionType : LineScreenFunctionType.values()) { + if (lineScreenFunctionType.isSameFunctionCode(Integer.parseInt(userInput))) { + lineScreenFunctionType.execute(); + } + } + } + + private static void validateUserInput(String userInput) { + validateUserInputLength(userInput); + char characterizedUserInput = userInput.charAt(FIRST_CHARACTER); + if (!isUserInputBack(characterizedUserInput)) { + validateUserInputRange(characterizedUserInput); + } + } + + private static void validateUserInputLength(String userInput) { + if (userInput.length() != INTEGER_ONE) { + System.out.println(userInput.length()); + throw new IllegalArgumentException(CANNOT_SELECT_MESSAGE); + } + } + + private static boolean isUserInputBack(char userInput) { + return Character.toUpperCase(userInput) == BACK; + } + + private static void validateUserInputRange(char userInput) { + if ((userInput < ONE || userInput > THREE)) { + throw new IllegalArgumentException(CANNOT_SELECT_MESSAGE); + } + } + + public static void registerLine() { + System.out.println(REGISTER_LINE_MESSAGE); + String lineName = scanner.nextLine(); + try { + validateLineName(lineName); + makeNewLine(lineName); + System.out.println(REGISTER_COMPLETE_MESSAGE); + System.out.println(); + } catch (Exception e) { + System.out.println(); + System.out.println(e.getMessage()); + registerLine(); + } + } + + private static void makeNewLine(String lineName) { + Line newLine = new Line(lineName); + Station upwardTerminalStation = getUpwardTerminalStation(); + Station downwardTerminalStation = getDownwardTerminalStation(); + validateAreStationSame(upwardTerminalStation, downwardTerminalStation); + newLine.registerStation(upwardTerminalStation); + newLine.registerStation(downwardTerminalStation); + LineRepository.addLine(newLine); + } + + private static void validateAreStationSame(Station upwardTerminalStation, Station downwardTerminalStation) { + if (upwardTerminalStation.equals(downwardTerminalStation)) { + throw new IllegalArgumentException("상행 종점과 하행 종점끼리 같은 역일 수 없습니다."); + } + } + + private static Station getUpwardTerminalStation() { + System.out.println("## 등록할 노선의 상행 종점역 이름을 입력하세요."); + String upwardTerminalStation = scanner.nextLine(); + try { + validateStationExistence(upwardTerminalStation); + + } catch (Exception e) { + System.out.println(e.getMessage()); + getUpwardTerminalStation(); + } + return new Station(upwardTerminalStation); + } + + private static Station getDownwardTerminalStation() { + System.out.println("## 등록할 노선의 하행 종점역 이름을 입력하세요."); + String downwardTerminalStation = scanner.nextLine(); + try { + validateStationExistence(downwardTerminalStation); + + } catch (Exception e) { + System.out.println(e.getMessage()); + getDownwardTerminalStation(); + } + return new Station(downwardTerminalStation); + } + + private static void validateStationExistence(String stationName) { + if (!StationRepository.isStationExist(stationName)) { + throw new IllegalArgumentException("존재하지 않는 역입니다."); + } + } + + public static void removeLine() { + System.out.println(REMOVE_LINE_MESSAGE); + String lineName = scanner.nextLine(); + try { + LineRepository.isLineExist(lineName); + LineRepository.deleteLineByName(lineName); + } catch (Exception e) { + System.out.println(); + System.out.println(e.getMessage()); + getLineScreenUserSelection(); + } + } + + private static void validateLineName(String lineName) { + validateLineNameLength(lineName); + validateLineNameEndedWithLine(lineName); + validateLineNameHasNumber(lineName); + validateLineNameHasOnlyKorean(lineName); + validateLineNameHasSpace(lineName); + validateLineNameHasDuplication(lineName); + } + + private static void validateLineNameLength(String lineName) { + if (lineName.length() < MINIMUM_LINE_NAME_LENGTH) { + throw new IllegalArgumentException(LINE_NAME_LENGTH_MESSAGE); + } + } + + private static void validateLineNameEndedWithLine(String lineName) { + if (!(lineName.charAt(lineName.length() - INTEGER_ONE) == LINE_NAME_ENDED_WITH)) { + throw new IllegalArgumentException(LINE_NAME_SHOULD_BE_ENDED_WITH_LINE_MESSAGE); + } + } + + private static void validateLineNameHasNumber(String lineName) { + if (lineName.matches(HAS_NUMBER_REGULAR_EXPRESSION)) { + throw new IllegalArgumentException(LINE_NAME_INCLUDE_NUMBER_MESSAGE); + } + } + + private static void validateLineNameHasOnlyKorean(String lineName) { + if (!lineName.matches(KOREAN_REGULAR_EXPRESSION)) { + throw new IllegalArgumentException(LINE_NAME_INCLUDE_NOT_KOREAN_MESSAGE); + } + } + + private static void validateLineNameHasSpace(String lineName) { + if (lineName.contains(SPACE)) { + throw new IllegalArgumentException(LINE_NAME_INCLUDE_SPACE_MESSAGE); + } + } + + private static void validateLineNameHasDuplication(String lineName) { + for (Line line : LineRepository.lines()) { + if (line.isSameName(lineName)) { + throw new IllegalArgumentException(LINE_NAME_HAS_DUPLICATION_MESSAGE); + } + } + } +} diff --git a/src/main/java/subway/view/LineOutputView.java b/src/main/java/subway/view/LineOutputView.java new file mode 100644 index 000000000..e075ad644 --- /dev/null +++ b/src/main/java/subway/view/LineOutputView.java @@ -0,0 +1,22 @@ +package subway.view; + +public class LineOutputView { + private static final String MANAGE_LINE_SCREEN = "## 노선 관리 화면"; + private static final String REGISTER_LINE = "1. 노선 등록"; + private static final String REMOVE_LINE = "2. 노선 삭제"; + private static final String PRINT_LINE = "3. 노선 조회"; + private static final String BACK = "B. 돌아가기"; + + private LineOutputView() { + } + + public static void printManageLineScreen() { + System.out.println(); + System.out.println(MANAGE_LINE_SCREEN); + System.out.println(REGISTER_LINE); + System.out.println(REMOVE_LINE); + System.out.println(PRINT_LINE); + System.out.println(BACK); + System.out.println(); + } +} diff --git a/src/main/java/subway/view/MainScreenInputView.java b/src/main/java/subway/view/MainScreenInputView.java new file mode 100644 index 000000000..3b5aa4f49 --- /dev/null +++ b/src/main/java/subway/view/MainScreenInputView.java @@ -0,0 +1,68 @@ +package subway.view; + +import subway.type.MainScreenFunctionType; + +import java.util.Scanner; + +public class MainScreenInputView { + private static final String SELECT_MESSAGE = "## 원하는 기능을 선택하세요."; + private static final String CANNOT_SELECT_MESSAGE = "[ERROR] 선택할 수 없는 기능입니다."; + private static final char ONE = '1'; + private static final int INTEGER_ONE = 1; + private static final char FOUR = '4'; + private static final char QUIT = 'Q'; + private static final int FIRST_CHARACTER = 0; + + private MainScreenInputView() { + } + + public static boolean getMainScreenUserSelection(Scanner scanner) { + MainScreenOutputView.printMainScreen(); + System.out.println(SELECT_MESSAGE); + String userInput = scanner.nextLine(); + try { + validateUserInput(userInput); + if (isUserInputQuit(userInput.charAt(FIRST_CHARACTER))) { + return false; + } + executeFunction(userInput); + } catch (Exception e) { + System.out.println(); + System.out.println(e.getMessage()); + getMainScreenUserSelection(scanner); + } + return true; + } + + private static void executeFunction(String userInput) { + for (MainScreenFunctionType mainScreenFunctionType : MainScreenFunctionType.values()) { + if (mainScreenFunctionType.isSameFunctionCode(Integer.parseInt(userInput))) { + mainScreenFunctionType.execute(); + } + } + } + + private static void validateUserInput(String userInput) { + validateUserInputLength(userInput); + char characterizedUserInput = userInput.charAt(FIRST_CHARACTER); + if (!isUserInputQuit(characterizedUserInput)) { + validateUserInputRange(characterizedUserInput); + } + } + + private static void validateUserInputLength(String userInput) { + if (userInput.length() != INTEGER_ONE) { + throw new IllegalArgumentException(CANNOT_SELECT_MESSAGE); + } + } + + private static boolean isUserInputQuit(char userInput) { + return Character.toUpperCase(userInput) == QUIT; + } + + private static void validateUserInputRange(char userInput) { + if ((userInput < ONE || userInput > FOUR)) { + throw new IllegalArgumentException(CANNOT_SELECT_MESSAGE); + } + } +} diff --git a/src/main/java/subway/view/MainScreenOutputView.java b/src/main/java/subway/view/MainScreenOutputView.java new file mode 100644 index 000000000..8477bb5c8 --- /dev/null +++ b/src/main/java/subway/view/MainScreenOutputView.java @@ -0,0 +1,23 @@ +package subway.view; + +public class MainScreenOutputView { + private static final String MAIN_SCREEN = "## 메인 화면"; + private static final String MANAGE_STATION = "1. 역 관리"; + private static final String MANAGE_LINE = "2. 노선 관리"; + private static final String MANAGE_SECTION = "3. 구간 관리"; + private static final String PRINT_MAP = "4. 지하철 노선도 출력"; + private static final String QUIT = "Q. 종료"; + + private MainScreenOutputView() { + } + + public static void printMainScreen() { + System.out.println(MAIN_SCREEN); + System.out.println(MANAGE_STATION); + System.out.println(MANAGE_LINE); + System.out.println(MANAGE_SECTION); + System.out.println(PRINT_MAP); + System.out.println(QUIT); + System.out.println(); + } +} diff --git a/src/main/java/subway/view/SectionInputView.java b/src/main/java/subway/view/SectionInputView.java new file mode 100644 index 000000000..55802e603 --- /dev/null +++ b/src/main/java/subway/view/SectionInputView.java @@ -0,0 +1,190 @@ +package subway.view; + +import subway.domain.Line; +import subway.domain.LineRepository; +import subway.domain.Station; +import subway.domain.StationRepository; +import subway.type.SectionScreenFunctionType; + +import java.util.Scanner; + +public class SectionInputView { + private static final String SELECT_MESSAGE = "## 원하는 기능을 선택하세요."; + private static final String CANNOT_SELECT_MESSAGE = "[ERROR] 선택할 수 없는 기능입니다."; + private static final String INPUT_LINE_MESSAGE = "## 노선을 입력하세요."; + private static final String DELETE_LINE_MESSAGE = "## 삭제할 구간의 노선을 입력하세요."; + private static final String DELETE_STATION_MESSAGE = "## 삭제할 구간의 역을 입력하세요."; + private static final String INPUT_STATION_MESSAGE = "## 역 이름을 입력하세요."; + private static final String INPUT_ORDER_MESSAGE = "## 순서를 입력하세요."; + private static final String SECTION_REMOVAL_MESSAGE = "[INFO] 구간이 삭제되었습니다."; + private static final String STATION_NOT_EXIST = "[ERROR] 노선에 역이 존재하지 않습니다."; + private static final String INVALID_ORDER_MESSAGE = "[ERROR] 순서는 양수이며 노선에 포함된 역의 개수 이하여야 합니다."; + private static final String INVALID_STATION_MESSAGE = "[ERROR] 노선에 이미 등록되어 있는 역이므로 등록이 불가능합니다."; + private static final int INTEGER_ONE = 1; + private static final char BACK = 'B'; + private static final int FIRST_CHARACTER = 0; + private static final char ONE = '1'; + private static final char TWO = '2'; + + private static final Scanner scanner = new Scanner(System.in); + + private SectionInputView() { + } + + public static void getSectionScreenUserSelection() { + SectionOutputView.printManageSectionScreen(); + System.out.println(SELECT_MESSAGE); + String userInput = scanner.nextLine(); + try { + validateUserInput(userInput); + if (isUserInputBack(userInput.charAt(FIRST_CHARACTER))) { + MainScreenInputView.getMainScreenUserSelection(scanner); + return; + } + executeFunction(userInput); + } catch (Exception e) { + System.out.println(); + System.out.println(e.getMessage()); + getSectionScreenUserSelection(); + } + } + + private static void executeFunction(String userInput) { + for (SectionScreenFunctionType sectionScreenFunctionType : SectionScreenFunctionType.values()) { + if (sectionScreenFunctionType.isSameFunctionCode(Integer.parseInt(userInput))) { + sectionScreenFunctionType.execute(); + } + } + } + + private static boolean isUserInputBack(char userInput) { + return Character.toUpperCase(userInput) == BACK; + } + + private static void validateUserInput(String userInput) { + validateUserInputLength(userInput); + char characterizedUserInput = userInput.charAt(FIRST_CHARACTER); + if (!isUserInputBack(characterizedUserInput)) { + validateUserInputRange(characterizedUserInput); + } + } + + private static void validateUserInputLength(String userInput) { + if (userInput.length() != INTEGER_ONE) { + System.out.println(userInput.length()); + throw new IllegalArgumentException(CANNOT_SELECT_MESSAGE); + } + } + + private static void validateUserInputRange(char userInput) { + if ((userInput < ONE || userInput > TWO)) { + throw new IllegalArgumentException(CANNOT_SELECT_MESSAGE); + } + } + + public static void registerSection() { // TODO 순서가 노선 size 넘어가면 안됨 + try { + System.out.println(INPUT_LINE_MESSAGE); + String lineName = getLineName(); + System.out.println(INPUT_STATION_MESSAGE); + String stationName = getStationName(); + validateStationRegisteredNotOnLine(lineName, stationName); + int order = getOrder(lineName); + insertStation(lineName, stationName, order); + } catch (Exception e) { + System.out.println(e.getMessage()); + getSectionScreenUserSelection(); + } + } + + private static void insertStation(String lineName, String stationName, int order) { + for (Line line : LineRepository.lines()) { + if (line.getName().equals(lineName)) { + line.insert(new Station(stationName), order); + } + } + } + + private static int getOrder(String lineName) { + System.out.println(INPUT_ORDER_MESSAGE); + int order = scanner.nextInt(); + if (INTEGER_ONE > order || getSizeOfLine(lineName) < order) { + throw new IllegalArgumentException(INVALID_ORDER_MESSAGE); + } + return order; + } + + private static int getSizeOfLine(String lineName) { + for (Line line : LineRepository.lines()) { + if (line.getName().equals(lineName)) { + return line.getSize(); + } + } + return -1; + } + + private static String getLineName() { + String lineName = scanner.nextLine(); + LineRepository.isLineExist(lineName); + return lineName; + } + + private static String getStationName() { + String stationName = scanner.nextLine(); + validateStationExistence(stationName); + return stationName; + } + + private static void validateStationExistence(String stationName) { + if (!StationRepository.isStationExist(stationName)) { + throw new IllegalArgumentException(INVALID_ORDER_MESSAGE); + } + } + + private static void validateStationRegisteredNotOnLine(String lineName, String stationName) { + for (Line line : LineRepository.lines()) { + if (line.getName().equals(lineName) && line.isStationRegistered(stationName)) { + throw new IllegalArgumentException(INVALID_STATION_MESSAGE); + } + } + } + + public static void removeSection() { + System.out.println(DELETE_LINE_MESSAGE); + try { + String lineName = getLineName(); + System.out.println(DELETE_STATION_MESSAGE); + String stationName = scanner.nextLine(); + validateStationOnLine(lineName, stationName); + removeStation(lineName, stationName); + System.out.println(SECTION_REMOVAL_MESSAGE); + } catch (Exception e) { + System.out.println(e.getMessage()); + getSectionScreenUserSelection(); + } + + } + + private static void removeStation(String lineName, String stationName) { + for (Line line : LineRepository.lines()) { + if (line.getName().equals(lineName)) { + line.remove(stationName); + } + } + } + + private static void validateStationOnLine(String lineName, String stationName) { + if (!isStationOnLine(lineName, stationName)) { + throw new IllegalArgumentException(STATION_NOT_EXIST); + } + } + + private static boolean isStationOnLine(String lineName, String stationName) { + for (Line line : LineRepository.lines()) { + if (line.getName().equals(lineName) && line.isStationRegistered(stationName)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/subway/view/SectionOutputView.java b/src/main/java/subway/view/SectionOutputView.java new file mode 100644 index 000000000..d0135b3f3 --- /dev/null +++ b/src/main/java/subway/view/SectionOutputView.java @@ -0,0 +1,20 @@ +package subway.view; + +public class SectionOutputView { + private static final String MANAGE_SECTION_SCREEN = "## 구간 관리 화면"; + private static final String REGISTER_SECTION = "1. 구간 등록"; + private static final String REMOVE_SECTION = "2. 구간 삭제"; + private static final String BACK = "B. 돌아가기"; + + private SectionOutputView() { + } + + public static void printManageSectionScreen() { + System.out.println(); + System.out.println(MANAGE_SECTION_SCREEN); + System.out.println(REGISTER_SECTION); + System.out.println(REMOVE_SECTION); + System.out.println(BACK); + System.out.println(); + } +} diff --git a/src/main/java/subway/view/StationInputView.java b/src/main/java/subway/view/StationInputView.java new file mode 100644 index 000000000..e3274b3c2 --- /dev/null +++ b/src/main/java/subway/view/StationInputView.java @@ -0,0 +1,169 @@ +package subway.view; + +import subway.domain.Line; +import subway.domain.LineRepository; +import subway.domain.Station; +import subway.domain.StationRepository; +import subway.type.StationScreenFunctionType; + +import java.util.Scanner; + +public class StationInputView { + private static final String SELECT_MESSAGE = "## 원하는 기능을 선택하세요."; + private static final String CANNOT_SELECT_MESSAGE = "[ERROR] 선택할 수 없는 기능입니다."; + private static final String REGISTER_STATION_MESSAGE = "## 등록할 역 이름을 입력하세요."; + private static final String REGISTER_COMPLETE_MESSAGE = "[INFO] 지하철 역이 등록되었습니다."; + private static final String REMOVE_STATION_MESSAGE = "## 삭제할 역 이름을 입력하세요."; + private static final char STATION_NAME_ENDED_WITH = '역'; + private static final String STATION_NAME_LENGTH_MESSAGE = "[ERROR] 역 이름은 두 글자 이상이어야 합니다."; + private static final String STATION_NAME_INCLUDE_NOT_KOREAN_MESSAGE = "[ERROR] 역 이름은 한글이어야 합니다."; + private static final String STATION_NAME_SHOULD_BE_ENDED_WITH_STATION_MESSAGE = "[ERROR] 역 이름 맨 뒤에 '역'을 붙여주세요."; + private static final String STATION_NAME_INCLUDE_NUMBER_MESSAGE = "[ERROR] 역 이름에 숫자를 포함하면 안 됩니다."; + private static final String STATION_NAME_INCLUDE_SPACE_MESSAGE = "[ERROR] 역 이름에 공백을 포함하면 안 됩니다."; + private static final String STATION_NAME_HAS_DUPLICATION_MESSAGE = "[ERROR] 이미 등록되어 있는 역입니다."; + private static final char ONE = '1'; + private static final char MINIMUM_STATION_NAME_LENGTH = 2; + private static final char THREE = '3'; + private static final char BACK = 'B'; + private static final String SPACE = " "; + private static final int FIRST_CHARACTER = 0; + private static final String KOREAN_REGULAR_EXPRESSION = "^[가-힣]*$"; + private static final String HAS_NUMBER_REGULAR_EXPRESSION = ".*[0-9].*"; + + private static final Scanner scanner = new Scanner(System.in); + + private StationInputView() { + } + + public static void getStationScreenUserSelection() { + StationOutputView.printManageStationScreen(); + System.out.println(SELECT_MESSAGE); + String userInput = scanner.nextLine(); + try { + validateUserInput(userInput); + if (isUserInputBack(userInput.charAt(FIRST_CHARACTER))) { + MainScreenInputView.getMainScreenUserSelection(scanner); + return; + } + executeFunction(userInput); + } catch (Exception e) { + System.out.println(); + System.out.println(e.getMessage()); + getStationScreenUserSelection(); + } + } + + private static void executeFunction(String userInput) { + for (StationScreenFunctionType stationScreenFunctionType : StationScreenFunctionType.values()) { + if (stationScreenFunctionType.isSameFunctionCode(Integer.parseInt(userInput))) { + stationScreenFunctionType.execute(); + } + } + } + + private static void validateUserInput(String userInput) { + validateUserInputLength(userInput); + char characterizedUserInput = userInput.charAt(FIRST_CHARACTER); + if (!isUserInputBack(characterizedUserInput)) { + validateUserInputRange(characterizedUserInput); + } + } + + private static void validateUserInputLength(String userInput) { + if (userInput.length() != 1) { + throw new IllegalArgumentException(CANNOT_SELECT_MESSAGE); + } + } + + private static boolean isUserInputBack(char userInput) { + return Character.toUpperCase(userInput) == BACK; + } + + private static void validateUserInputRange(char userInput) { + if ((userInput < ONE || userInput > THREE)) { + throw new IllegalArgumentException(CANNOT_SELECT_MESSAGE); + } + } + + public static void registerStation() { + System.out.println(REGISTER_STATION_MESSAGE); + String stationName = scanner.nextLine(); + try { + validateStationName(stationName); + StationRepository.addStation(new Station(stationName)); + System.out.println(REGISTER_COMPLETE_MESSAGE); + } catch (Exception e) { + System.out.println(); + System.out.println(e.getMessage()); + registerStation(); + } + } + + public static void removeStation() { + System.out.println(REMOVE_STATION_MESSAGE); + String stationName = scanner.nextLine(); + try { // TODO 노선에 포함된 역이 두 개 이하이면 역을 삭제할 수 없다. + validateStationRegisteredOnLine(stationName); + StationRepository.deleteStation(stationName); + } catch (Exception e) { + System.out.println(); + System.out.println(e.getMessage()); + getStationScreenUserSelection(); + } + } + + private static void validateStationRegisteredOnLine(String stationName) { + for (Line line : LineRepository.lines()) { + if (line.isStationRegistered(stationName)) { + throw new IllegalArgumentException("[ERROR] 노선에 등록되어 있는 역이므로 삭제가 불가능합니다."); + } + } + } + + private static void validateStationName(String stationName) { + validateStationNameLength(stationName); + validateStationNameEndedWithStation(stationName); + validateStationNameHasNumber(stationName); + validateStationNameHasOnlyKorean(stationName); + validateStationNameHasSpace(stationName); + validateStationNameHasDuplication(stationName); + } + + private static void validateStationNameLength(String stationName) { + if (stationName.length() < MINIMUM_STATION_NAME_LENGTH) { + throw new IllegalArgumentException(STATION_NAME_LENGTH_MESSAGE); + } + } + + private static void validateStationNameEndedWithStation(String stationName) { + if (!(stationName.charAt(stationName.length() - 1) == STATION_NAME_ENDED_WITH)) { + throw new IllegalArgumentException(STATION_NAME_SHOULD_BE_ENDED_WITH_STATION_MESSAGE); + } + } + + private static void validateStationNameHasNumber(String stationName) { + if (stationName.matches(HAS_NUMBER_REGULAR_EXPRESSION)) { + throw new IllegalArgumentException(STATION_NAME_INCLUDE_NUMBER_MESSAGE); + } + } + + private static void validateStationNameHasOnlyKorean(String stationName) { + if (!stationName.matches(KOREAN_REGULAR_EXPRESSION)) { + throw new IllegalArgumentException(STATION_NAME_INCLUDE_NOT_KOREAN_MESSAGE); + } + } + + private static void validateStationNameHasSpace(String stationName) { + if (stationName.contains(SPACE)) { + throw new IllegalArgumentException(STATION_NAME_INCLUDE_SPACE_MESSAGE); + } + } + + private static void validateStationNameHasDuplication(String stationName) { + for (Station station : StationRepository.stations()) { + if (station.isSameName(stationName)) { + throw new IllegalArgumentException(STATION_NAME_HAS_DUPLICATION_MESSAGE); + } + } + } +} diff --git a/src/main/java/subway/view/StationOutputView.java b/src/main/java/subway/view/StationOutputView.java new file mode 100644 index 000000000..315042b26 --- /dev/null +++ b/src/main/java/subway/view/StationOutputView.java @@ -0,0 +1,22 @@ +package subway.view; + +public class StationOutputView { + private static final String MANAGE_STATION_SCREEN = "## 역 관리 화면"; + private static final String REGISTER_STATION = "1. 역 등록"; + private static final String REMOVE_STATION = "2. 역 삭제"; + private static final String PRINT_STATION = "3. 역 조회"; + private static final String BACK = "B. 돌아가기"; + + private StationOutputView() { + } + + public static void printManageStationScreen() { + System.out.println(); + System.out.println(MANAGE_STATION_SCREEN); + System.out.println(REGISTER_STATION); + System.out.println(REMOVE_STATION); + System.out.println(PRINT_STATION); + System.out.println(BACK); + System.out.println(); + } +}