ShipSelectionScreen::ShipSelectionScreen()
{
    //Easiest place to ensure that positional sound is disabled on console views. As soon as a 3D view is rendered positional sound is enabled again.
    soundManager->disablePositionalSound();

    (new GuiLabel(this, "CREW_POSITION_SELECT_LABEL", "Select your station", 30))->addBox()->setPosition(-50, 50, ATopRight)->setSize(460, 50);
    (new GuiBox(this, "CREW_POSITION_SELECT_BOX"))->setPosition(-50, 50, ATopRight)->setSize(460, 560);
    
    GuiAutoLayout* stations_layout = new GuiAutoLayout(this, "CREW_POSITION_BUTTON_LAYOUT", GuiAutoLayout::LayoutVerticalTopToBottom);
    stations_layout->setPosition(-80, 100, ATopRight)->setSize(400, 500);
    main_screen_button = new GuiToggleButton(stations_layout, "MAIN_SCREEN_BUTTON", "Main screen", [this](bool value) {
        for(int n=0; n<max_crew_positions; n++)
        {
            crew_position_button[n]->setValue(false);
            my_player_info->setCrewPosition(ECrewPosition(n), crew_position_button[n]->getValue());
        }
        updateReadyButton();
    });
    main_screen_button->setSize(GuiElement::GuiSizeMax, 50);
    for(int n=0; n<max_crew_positions; n++)
    {
        crew_position_button[n] = new GuiToggleButton(stations_layout, "CREW_" + getCrewPositionName(ECrewPosition(n)) + "_BUTTON", getCrewPositionName(ECrewPosition(n)), [this, n](bool value){
            main_screen_button->setValue(false);
            my_player_info->setCrewPosition(ECrewPosition(n), value);
            updateReadyButton();
        });
        crew_position_button[n]->setSize(GuiElement::GuiSizeMax, 50);
    }

    main_screen_controls_button = new GuiToggleButton(stations_layout, "MAIN_SCREEN_CONTROLS_ENABLE", "Main screen controls", [](bool value) {
        my_player_info->setMainScreenControl(value);
    });
    main_screen_controls_button->setValue(my_player_info->main_screen_control)->setSize(GuiElement::GuiSizeMax, 50);
    
    game_master_button = new GuiToggleButton(stations_layout, "GAME_MASTER_BUTTON", "Game master", [this](bool value) {
        window_button->setValue(false);
        topdown_button->setValue(false);
        updateReadyButton();
    });
    game_master_button->setSize(GuiElement::GuiSizeMax, 50);
    window_button = new GuiToggleButton(stations_layout, "WINDOW_BUTTON", "Ship window", [this](bool value) {
        game_master_button->setValue(false);
        topdown_button->setValue(false);
        updateReadyButton();
    });
    window_button->setSize(GuiElement::GuiSizeMax, 50);
    window_angle = new GuiSelector(stations_layout, "WINDOW_ANGLE", nullptr);
    for(int n=0; n<360; n+=15)
        window_angle->addEntry(string(n) + " degrees", string(n));
    window_angle->setSelectionIndex(0);
    window_angle->setSize(GuiElement::GuiSizeMax, 50);
    topdown_button = new GuiToggleButton(stations_layout, "TOP_DOWN_3D_BUTTON", "Top down 3D", [this](bool value) {
        game_master_button->setValue(false);
        window_button->setValue(false);
        updateReadyButton();
    });
    topdown_button->setSize(GuiElement::GuiSizeMax, 50);
    
    crew_type_selector = new GuiSelector(this, "CREW_TYPE_SELECTION", [this](int index, string value) {
        updateCrewTypeOptions();
    });
    crew_type_selector->setOptions({"6/5 player crew", "4/3 player crew", "1 player crew/extras", "Alternative options"})->setPosition(-50, 560, ATopRight)->setSize(460, 50);
    
    (new GuiLabel(this, "SHIP_SELECTION_LABEL", "Select ship:", 30))->addBox()->setPosition(50, 50, ATopLeft)->setSize(550, 50);
    no_ships_label = new GuiLabel(this, "SHIP_SELECTION_NO_SHIPS_LABEL", "Waiting for server to spawn a ship", 30);
    no_ships_label->setPosition(80, 100, ATopLeft)->setSize(460, 50);
    (new GuiBox(this, "SHIP_SELECTION_BOX"))->setPosition(50, 50, ATopLeft)->setSize(550, 560);
    player_ship_list = new GuiListbox(this, "PLAYER_SHIP_LIST", [this](int index, string value) {
        my_spaceship = gameGlobalInfo->getPlayerShip(value.toInt());
        if (my_spaceship)
        {
            my_player_info->setShipId(my_spaceship->getMultiplayerId());
        }else{
            my_player_info->setShipId(-1);
        }
        updateReadyButton();
    });
    player_ship_list->setPosition(80, 100, ATopLeft)->setSize(490, 500);


    if (game_server)
    {
        (new GuiBox(this, "CREATE_SHIP_BOX"))->setPosition(50, 50, ATopLeft)->setSize(550, 700);
        GuiSelector* ship_template_selector = new GuiSelector(this, "CREATE_SHIP_SELECTOR", nullptr);
        std::vector<string> template_names = ShipTemplate::getPlayerTemplateNameList();
        std::sort(template_names.begin(), template_names.end());
        ship_template_selector->setOptions(template_names)->setSelectionIndex(0);
        ship_template_selector->setPosition(80, 630, ATopLeft)->setSize(490, 50);
        
        (new GuiButton(this, "CREATE_SHIP_BUTTON", "Spawn player ship", [this, ship_template_selector]() {
            my_spaceship = new PlayerSpaceship();
            if (my_spaceship)
            {
                my_spaceship->setShipTemplate(ship_template_selector->getSelectionValue());
                my_spaceship->setRotation(random(0, 360));
                my_spaceship->target_rotation = my_spaceship->getRotation();
                my_spaceship->setPosition(sf::Vector2f(random(-100, 100), random(-100, 100)));
                my_player_info->setShipId(my_spaceship->getMultiplayerId());
            }
            updateReadyButton();
        }))->setPosition(80, 680, ATopLeft)->setSize(490, 50);
    }
    
    (new GuiButton(this, "DISCONNECT", game_server ? "Close server" : "Disconnect", [this]() {
        destroy();
        disconnectFromServer();
        returnToMainMenu();
    }))->setPosition(150, -50, ABottomLeft)->setSize(300, 50);
    ready_button = new GuiButton(this, "READY_BUTTON", "Ready", [this]() {this->onReadyClick();});
    ready_button->setPosition(-150, -50, ABottomRight)->setSize(300, 50);
    
    crew_type_selector->setSelectionIndex(0);
    updateReadyButton();
    updateCrewTypeOptions();
}
ShipSelectionScreen::ShipSelectionScreen()
{
    new GuiOverlay(this, "", colorConfig.background);
    (new GuiOverlay(this, "", sf::Color::White))->setTextureTiled("gui/BackgroundCrosses");

    // Easiest place to ensure that positional sound is disabled on console
    // views. As soon as a 3D view is rendered, positional sound is re-enabled.
    soundManager->disablePositionalSound();

    // Draw a container with two columns.
    container = new GuiAutoLayout(this, "", GuiAutoLayout::ELayoutMode::LayoutVerticalColumns);
    container->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax);
    left_container = new GuiElement(container, "");
    right_container = new GuiElement(container, "");

    // List the station types and stations in the right column.
    GuiAutoLayout* stations_layout = new GuiAutoLayout(right_container, "CREW_POSITION_BUTTON_LAYOUT", GuiAutoLayout::LayoutVerticalTopToBottom);
    stations_layout->setPosition(0, 50, ATopCenter)->setSize(400, 500);
    (new GuiLabel(stations_layout, "CREW_POSITION_SELECT_LABEL", "Select your station", 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50);

    // Crew type selector
    crew_type_selector = new GuiSelector(stations_layout, "CREW_TYPE_SELECTION", [this](int index, string value) {
        updateCrewTypeOptions();
    });
    crew_type_selector->setOptions({"6/5 player crew", "4/3 player crew", "1 player crew/extras", "Alternative options"})->setSize(GuiElement::GuiSizeMax, 50);

    // Main screen button
    main_screen_button = new GuiToggleButton(stations_layout, "MAIN_SCREEN_BUTTON", "Main screen", [this](bool value) {
        for(int n=0; n<max_crew_positions; n++)
        {
            crew_position_button[n]->setValue(false);
            my_player_info->commandSetCrewPosition(ECrewPosition(n), crew_position_button[n]->getValue());
        }
    });
    main_screen_button->setSize(GuiElement::GuiSizeMax, 50);

    // Crew position buttons, with icons if they have them
    for(int n = 0; n < max_crew_positions; n++)
    {
        crew_position_button[n] = new GuiToggleButton(stations_layout, "CREW_" + getCrewPositionName(ECrewPosition(n)) + "_BUTTON", getCrewPositionName(ECrewPosition(n)), [this, n](bool value){
            main_screen_button->setValue(false);
            my_player_info->commandSetCrewPosition(ECrewPosition(n), value);
        });
        crew_position_button[n]->setSize(GuiElement::GuiSizeMax, 50);
        crew_position_button[n]->setIcon(getCrewPositionIcon(ECrewPosition(n)));
    }

    // Main screen controls button
    main_screen_controls_button = new GuiToggleButton(stations_layout, "MAIN_SCREEN_CONTROLS_ENABLE", "Main screen controls", [](bool value) {
        my_player_info->commandSetMainScreenControl(value);
    });
    main_screen_controls_button->setValue(my_player_info->main_screen_control)->setSize(GuiElement::GuiSizeMax, 50);
    
    // Game master button
    game_master_button = new GuiToggleButton(stations_layout, "GAME_MASTER_BUTTON", "Game master", [this](bool value) {
        window_button->setValue(false);
        topdown_button->setValue(false);
        cinematic_view_button->setValue(false);
    });
    game_master_button->setSize(GuiElement::GuiSizeMax, 50);

    // Ship window button and angle slider
    window_button_row = new GuiAutoLayout(stations_layout, "", GuiAutoLayout::LayoutHorizontalLeftToRight);
    window_button_row->setSize(GuiElement::GuiSizeMax, 50);
    window_button = new GuiToggleButton(window_button_row, "WINDOW_BUTTON", "Ship window", [this](bool value) {
        game_master_button->setValue(false);
        topdown_button->setValue(false);
        cinematic_view_button->setValue(false);
    });
    window_button->setSize(175, 50);

    window_angle = new GuiSlider(window_button_row, "WINDOW_ANGLE", 0.0, 359.0, 0.0, [this](float value) {
        window_angle_label->setText(string(int(window_angle->getValue())) + " degrees");
    });
    window_angle->setSize(GuiElement::GuiSizeMax, 50);
    window_angle_label = new GuiLabel(window_angle, "WINDOW_ANGLE_LABEL", "0 degrees", 30);
    window_angle_label->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax);

    // Top-down view button
    topdown_button = new GuiToggleButton(stations_layout, "TOP_DOWN_3D_BUTTON", "Top-down 3D view", [this](bool value) {
        game_master_button->setValue(false);
        window_button->setValue(false);
        cinematic_view_button->setValue(false);
    });
    topdown_button->setSize(GuiElement::GuiSizeMax, 50);

    // Cinematic view button
    cinematic_view_button = new GuiToggleButton(stations_layout, "CINEMATIC_VIEW_BUTTON", "Cinematic view", [this](bool value) {
        game_master_button->setValue(false);
        window_button->setValue(false);
        topdown_button->setValue(false);
    });
    cinematic_view_button->setSize(GuiElement::GuiSizeMax, 50);

    // If this is the server, add a panel to create player ships.
    if (game_server)
    {
        (new GuiPanel(left_container, "CREATE_SHIP_BOX"))->setPosition(0, 50, ATopCenter)->setSize(550, 700);
    }

    // Player ship selection panel
    (new GuiPanel(left_container, "SHIP_SELECTION_BOX"))->setPosition(0, 50, ATopCenter)->setSize(550, 560);
    (new GuiLabel(left_container, "SHIP_SELECTION_LABEL", "Select ship", 30))->addBackground()->setPosition(0, 50, ATopCenter)->setSize(510, 50);
    no_ships_label = new GuiLabel(left_container, "SHIP_SELECTION_NO_SHIPS_LABEL", "Waiting for server to spawn a ship", 30);
    no_ships_label->setPosition(0, 100, ATopCenter)->setSize(460, 50);

    // Player ship list
    player_ship_list = new GuiListbox(left_container, "PLAYER_SHIP_LIST", [this](int index, string value) {
        P<PlayerSpaceship> ship = gameGlobalInfo->getPlayerShip(value.toInt());

        // If the selected item is a ship ...
        if (ship)
        {
            // ... and it has a control code, ask the player for it.
            if (ship->control_code.length() > 0)
            {
                LOG(INFO) << "Player selected " << ship->getCallSign() << ", which has a control code.";
                // Hide the ship selection UI temporarily to deter sneaky ship thieves.
                left_container->hide();
                right_container->hide();
                // Show the control code entry dialog.
                password_overlay->show();
            }
            // Otherwise, select and set this ship ID in the player info.
            else
            {
                my_player_info->commandSetShipId(ship->getMultiplayerId());
            }
        // If the selected item isn't a ship, reset the ship ID in player info.
        }else{
            my_player_info->commandSetShipId(-1);
        }
    });
    player_ship_list->setPosition(0, 100, ATopCenter)->setSize(490, 500);

    // If this is the server, add buttons and a selector to create player ships.
    if (game_server)
    {
        GuiSelector* ship_template_selector = new GuiSelector(left_container, "CREATE_SHIP_SELECTOR", nullptr);
        // List only ships with templates designated for player use.
        std::vector<string> template_names = ShipTemplate::getTemplateNameList(ShipTemplate::PlayerShip);
        std::sort(template_names.begin(), template_names.end());

        for(string& template_name : template_names)
        {
            P<ShipTemplate> ship_template = ShipTemplate::getTemplate(template_name);
            ship_template_selector->addEntry(template_name + " (" + ship_template->getClass() + ":" + ship_template->getSubClass() + ")", template_name);
        }
        ship_template_selector->setSelectionIndex(0);
        ship_template_selector->setPosition(0, 630, ATopCenter)->setSize(490, 50);

        // Spawn a ship of the selected template near 0,0 and give it a random
        // heading.
        (new GuiButton(left_container, "CREATE_SHIP_BUTTON", "Spawn player ship", [this, ship_template_selector]() {
            P<PlayerSpaceship> ship = new PlayerSpaceship();

            if (ship)
            {
                ship->setTemplate(ship_template_selector->getSelectionValue());
                ship->setRotation(random(0, 360));
                ship->target_rotation = ship->getRotation();
                ship->setPosition(sf::Vector2f(random(-100, 100), random(-100, 100)));
                my_player_info->commandSetShipId(ship->getMultiplayerId());
            }
        }))->setPosition(0, 680, ATopCenter)->setSize(490, 50);

        // If this is the server, the "back" button goes to the scenario
        // selection/server creation screen.
        (new GuiButton(left_container, "DISCONNECT", "Scenario selection", [this]() {
            destroy();
            new ServerCreationScreen();
        }))->setPosition(0, -50, ABottomCenter)->setSize(300, 50);
    }else{
        // If this is a client, the "back" button disconnects from the server
        // and returns to the main menu.
        (new GuiButton(left_container, "DISCONNECT", "Disconnect", [this]() {
            destroy();
            disconnectFromServer();
            returnToMainMenu();
        }))->setPosition(0, -50, ABottomCenter)->setSize(300, 50);
    }

    // The "Ready" button.
    ready_button = new GuiButton(right_container, "READY_BUTTON", "Ready", [this]() {
        this->onReadyClick();
    });
    ready_button->setPosition(0, -50, ABottomCenter)->setSize(300, 50);

    // Set the crew type selector's default to 6/5 person crew screens.
    crew_type_selector->setSelectionIndex(0);
    updateCrewTypeOptions();

    // Control code entry dialog.
    password_overlay = new GuiOverlay(this, "PASSWORD_OVERLAY", sf::Color::Black - sf::Color(0, 0, 0, 192));
    password_overlay->hide();
    password_entry_box = new GuiPanel(password_overlay, "PASSWORD_ENTRY_BOX");
    password_entry_box->setPosition(0, 350, ATopCenter)->setSize(600, 200);
    password_label = new GuiLabel(password_entry_box, "PASSWORD_LABEL", "Enter this ship's control code:", 30);
    password_label->setPosition(0, 40, ATopCenter);
    password_entry = new GuiTextEntry(password_entry_box, "PASSWORD_ENTRY", "");
    password_entry->setPosition(20, 0, ACenterLeft)->setSize(400, 50);
    password_cancel = new GuiButton(password_entry_box, "PASSWORD_CANCEL_BUTTON", "Cancel", [this]() {
        // Reset the dialog.
        password_label->setText("Enter this ship's control code:");
        password_entry->setText("");
        // Hide the password overlay and show the ship selection screen.
        password_overlay->hide();
        left_container->show();
        right_container->show();
        // Unselect player ship if cancelling.
        player_ship_list->setSelectionIndex(-1);
        my_player_info->commandSetShipId(-1);
    });
    password_cancel->setPosition(0, -20, ABottomCenter)->setSize(300, 50);

    // Control code entry button.
    password_entry_ok = new GuiButton(password_entry_box, "PASSWORD_ENTRY_OK", "Ok", [this]()
    {
        P<PlayerSpaceship> ship = gameGlobalInfo->getPlayerShip(player_ship_list->getEntryValue(player_ship_list->getSelectionIndex()).toInt());

        if (ship)
        {
            // Get the password.
            string password = password_entry->getText();
            string control_code = ship->control_code;

            if (password != control_code)
            {
                // Password doesn't match. Unset the player ship selection.
                LOG(INFO) << "Password doesn't match control code. Attempt: " << password;
                my_player_info->commandSetShipId(-1);
                // Notify the player.
                password_label->setText("Incorrect control code. Re-enter code for " + ship->getCallSign() + ":");
                // Reset the dialog.
                password_entry->setText("");
            }
            else
            {
                // Password matches.
                LOG(INFO) << "Password matches control code.";
                // Set the player ship.
                my_player_info->commandSetShipId(ship->getMultiplayerId());
                // Notify the player.
                password_label->setText("Control code accepted.\nGranting access to " + ship->getCallSign() + ".");
                // Reset and hide the password field.
                password_entry->setText("");
                password_entry->hide();
                password_cancel->hide();
                password_entry_ok->hide();
                // Show a confirmation button.
                password_confirmation->show();
            }
        }
    });
    password_entry_ok->setPosition(420, 0, ACenterLeft)->setSize(160, 50);

    // Control code confirmation button
    password_confirmation = new GuiButton(password_entry_box, "PASSWORD_CONFIRMATION_BUTTON", "OK", [this]() {
        // Reset the dialog.
        password_entry->show();
        password_cancel->show();
        password_entry_ok->show();
        password_label->setText("Enter this ship's control code:")->setPosition(0, 40, ATopCenter);
        password_confirmation->hide();
        // Hide the dialog.
        password_overlay->hide();
        // Show the UI.
        left_container->show();
        right_container->show();
    });
    password_confirmation->setPosition(0, -20, ABottomCenter)->setSize(250, 50)->hide();
}