/*
 * 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 service;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Timer;
import java.util.TimerTask;

import org.linphone.core.Account;
import org.linphone.core.AccountParams;
import org.linphone.core.Address;
import org.linphone.core.AuthInfo;
import org.linphone.core.Call;
import org.linphone.core.CallParams;
import org.linphone.core.Core;
import org.linphone.core.CoreListenerStub;
import org.linphone.core.Factory;
import org.linphone.core.GlobalState;
import org.linphone.core.LogLevel;
import org.linphone.core.LoggingService;
import org.linphone.core.TransportType;
import org.linphone.core.VideoActivationPolicy;

import javafx.application.Platform;

public class CoreService extends CoreListenerStub {
    private static CoreService instance;

    public Core core;
    public IterateRunnable iterateRunnable;
    private Timer iterateTimer;

    private CoreService() {
        Factory factory = Factory.instance();
        factory.setDataDir(".");

        LoggingService loggingService = factory.getLoggingService();
        loggingService.setLogLevel(LogLevel.Message);

        core = factory.createCore("", "", null);
        core.setAudioPort(7666);
        core.setUserCertificatesPath(Paths.get("").toString());
    }

    public static CoreService instance() {
        if (instance == null) {
            instance = new CoreService();
        }
        return instance;
    }

    public void start() {
        this.core.start();
    
        // The iterate method of the Core is to be called regularly, typically at 20 ms interval.
        // So we create an IterateRunnable and a Timer to execute this call every 20 ms.
        iterateRunnable = new IterateRunnable();
        iterateTimer = new Timer();
        iterateTimer.schedule(new IterateTimerTask(), 20, 20);
    }

    public void stop() {
        core.stop();
    }

    public void login(String identity, String password, TransportType transport) {
        // To configure a SIP account, we need an Account object and an AuthInfo object.
        // The first one is how to connect to the proxy server, the second one stores the credentials.

        // Here we are creating an AuthInfo object from the identity Address and password provided by the user.
        Address address = Factory.instance().createAddress(identity);
        // The AuthInfo can be created from the Factory as it's only a data class.
	    // userID is set to "" as it's the same as the username in our case.
	    // ha1 is set to "" as we are using the clear text password. Upon first register, the hash will be computed automatically.
	     // The realm will be determined automatically from the first register, as well as the algorithm.
        AuthInfo authInfo = Factory.instance().createAuthInfo(address.getUsername(), "", password, "", "",
                address.getDomain());
        // And we add it to the Core.
        core.addAuthInfo(authInfo);

        // Then we create an AccountParams object.
	    // It contains the account informations needed by the core.
        AccountParams accountParams = core.createAccountParams();
        // A SIP account is identified by an identity address that we can construct from the username and domain.
        accountParams.setIdentityAddress(address);
        // We also need to configure where the proxy server is located.
        Address serverAddress = Factory.instance().createAddress("sip:" + address.getDomain());
        // We use the Address object to easily set the transport protocol.
        serverAddress.setTransport(transport);
        accountParams.setServerAddress(serverAddress);
        // If setRegisterEnabled(true), when this account will be added to the core it will automatically try to connect.
        accountParams.setRegisterEnabled(true);

        // We can now create an Account object from the AccountParams...
        Account account = core.createAccount(accountParams);
        // ... and add it to the core, launching the connection process.
        core.addAccount(account);
        // Also set the newly added account as default.
        core.setDefaultAccount(account);
    }

    public void logout() {
        // setRegisterEnabled(false) on a connected Account object will launch the logout action.
        Account account = core.getDefaultAccount();
        if (account != null) {
            // BUT BE CAREFUL : the Params attribute of an account is read-only, you MUST Clone it.
            AccountParams accountParams = account.getParams().clone();
            // Then you can modify the clone.
            accountParams.setRegisterEnabled(false);
            // And finally setting the new Params value triggers the changes, here the logout.
            account.setParams(accountParams);
        }
    }

    public void clearCoreAfterLogout() {
        core.clearAllAuthInfo();
        core.clearAccounts();
    }

    @Override
    public void onGlobalStateChanged(Core core, GlobalState state, String message) {
        if (state == GlobalState.Off) {
            iterateTimer.cancel();
        }
    }
}

class IterateTimerTask extends TimerTask {
    @Override
    public void run() {
        Platform.runLater(CoreService.instance().iterateRunnable);
    }
}

class IterateRunnable implements Runnable {
    @Override
    public void run() {
        CoreService.instance().core.iterate();
    }

}