/*
 * Copyright (c) 2010-2024 Belledonne Communications SARL.
 *
 * This file is part of Linphone Java Tutorial.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package controller;

import org.linphone.core.Call;
import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.Reason;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.VBox;
import service.CoreService;

public class CallController extends CoreListenerStub implements ScreenInterface {
    private CoreService coreService = CoreService.instance();
    private Call incomingCall;

    @FXML
    private TitledPane callPane;

    @FXML
    TextField uriToCallField;

    @FXML
    private Button callButton;

    @FXML
    private Button hangupButton;

    @FXML
    private Button cameraButton;

    @FXML
    private Button muteSoundButton;

    @FXML
    private Button muteMicrophoneButton;

    @FXML
    private VBox incomingCallVBox;

    @FXML
    private Label incomingCallLabel;

    @FXML
    private Button answerButton;

    @FXML
    private Button declineButton;

    @FXML
    private Label callLabel;

    @FXML
    private void onCallClicked() {
        coreService.call(uriToCallField.getText());
    }

    @FXML
    private void onHangUpClicked() {
        coreService.core.terminateAllCalls();
    }

    @FXML
    private void onCameraClicked() {
        coreService.toggleCamera();
        cameraButton.setText("Waiting...");
        cameraButton.setDisable(true);
    }

    @FXML
    private void onMuteSoundClicked() {
        if (coreService.toggleSpeaker()) {
            muteSoundButton.setText("Activate sound");
        } else {
            muteSoundButton.setText("Mute sound");
        }
    }

    @FXML
    private void onMuteMicrophoneClicked() {
        if (coreService.toggleMicrophone()) {
            muteMicrophoneButton.setText("Activate microphone");
        } else {
            muteMicrophoneButton.setText("Mute microphone");
        }
    }

    @FXML
    private void onAnswerClicked() {
        if (incomingCall == null)
            return;

        incomingCall.accept();
        incomingCall = null;
    }

    @FXML
    private void onDeclineClicked() {
        if (incomingCall == null)
            return;

        incomingCall.decline(Reason.Declined);
        incomingCall = null;
    }

    private void callInProgressGuiUpdates() {
        incomingCallVBox.setVisible(false);
        callButton.setDisable(true);
        hangupButton.setDisable(false);
        cameraButton.setDisable(false);
        muteSoundButton.setDisable(false);
        muteMicrophoneButton.setDisable(false);
    }

    private void endingCallGuiUpdates() {
        incomingCallVBox.setVisible(false);
        callButton.setDisable(false);
        hangupButton.setDisable(true);
        cameraButton.setDisable(true);
        cameraButton.setText("Activate camera");
        muteSoundButton.setDisable(true);
        muteSoundButton.setText("Mute sound");
        muteMicrophoneButton.setDisable(true);
        muteMicrophoneButton.setText("Mute microphone");
    }

    private void startVideoAndUpdateGui() {
        cameraButton.setText("Deactivate camera");
        callButton.setDisable(false);
    }

    private void stopVideoAndUpdateGui() {
        cameraButton.setText("Activate camera");
        cameraButton.setDisable(false);
    }

    public void onCallStateChanged(Core core, Call call, Call.State state, String message) {
        callLabel.setText("Your call state is: " + state.toString());
        switch (state) {
            case IncomingReceived:
                incomingCall = call;
                incomingCallVBox.setVisible(true);
                incomingCallLabel.setText(incomingCall.getRemoteAddress().asString());
                break;
            case OutgoingInit:
            case OutgoingProgress:
            case OutgoingRinging:
                hangupButton.setDisable(false);
                break;
            case StreamsRunning:
            case UpdatedByRemote:
                callInProgressGuiUpdates();
                if (call.getCurrentParams().isVideoEnabled()) {
                    startVideoAndUpdateGui();
                } else {
                    stopVideoAndUpdateGui();
                }
                break;
            case Error:
            case End:
            case Released:
                incomingCall = null;
                endingCallGuiUpdates();
                break;
            default:
                break;
        }
    }

    @Override
    public void onNavigatedFrom() {
        coreService.core.removeListener(this);
    }

    @Override
    public void onNavigatedTo() {
        callPane.setText("Hello " + coreService.core.getDefaultProxyConfig().findAuthInfo().getUsername());
        coreService.core.addListener(this);
        if (coreService.core.getCurrentCall() != null) {
            onCallStateChanged(coreService.core, coreService.core.getCurrentCall(),
                    coreService.core.getCurrentCall().getState(), null);
        }
    }
}
