// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//#![deny(warnings)]
#![feature(
    async_await,
    await_macro,
    futures_api,
    pin,
    arbitrary_self_types
)]

use failure::{Error, ResultExt};
use fidl::endpoints::{RequestStream, ServerEnd, ServiceMarker};
use fidl_fuchsia_telephony_ril::{RadioInterfaceLayerMarker, RadioInterfaceLayerRequest, RadioInterfaceLayerRequestStream};
use fidl_fuchsia_telephony_ril::RadioPowerState;
use fuchsia_app::server::ServicesServer;
use fuchsia_async as fasync;
use fuchsia_syslog::{self as syslog, macros::*};
use fuchsia_zircon as zx;
use futures::{TryFutureExt, TryStreamExt};
use qmi_protocol::QmiResult;

use parking_lot::{Mutex, RwLock};
use std::sync::Arc;

use crate::client::QmiClient;
use crate::transport::QmiTransport;
use crate::errors::QmuxError;
use qmi_protocol::CTL::*;
use qmi_protocol::*;

mod client;
mod errors;
mod service;
mod transport;

type QmiModemPtr = Arc<Mutex<QmiModem>>;
type QmiClientPtr = Arc<RwLock<QmiClient>>;

pub struct QmiModem {
    inner: Option<Arc<QmiTransport>>,
}

impl QmiModem {
    pub fn new() -> Self {
        QmiModem { inner: None }
    }

    pub fn connected(&self) -> bool {
        // TODO add aditional logic for checking transport_channel open
        self.inner.is_some()
    }

    pub fn connect_transport(&mut self, chan: zx::Channel) -> bool {
        fx_log_info!("Connecting the transport");
        if self.connected() {
            fx_log_err!("Attempted to connect more than one transport");
            return false;
        }
        match fasync::Channel::from_channel(chan) {
            Ok(chan) => {
                if chan.is_closed() {
                    fx_log_err!("The transport channel is not open");
                    return false;
                }
                self.inner = Some(Arc::new(QmiTransport::new(chan)));
                true
            }
            Err(_) => {
                fx_log_err!("Failed to convert a zircon channel to a fasync one");
                false
            }
        }
    }

    pub async fn create_client(&self) -> Result<QmiClient, Error> {
        fx_log_info!("Client connecting...");
        if let Some(ref inner) = self.inner {
            let transport_inner = inner.clone();
            let client = QmiClient::new(transport_inner);
            Ok(client)
        } else {
            Err(QmuxError::NoClient.into())
        }
    }
}

type ClientPtr = Arc<Mutex<Option<QmiClient>>>;

struct FrilService;
impl FrilService {
    pub fn spawn(modem: QmiModemPtr, chan: fasync::Channel) {
        let client = Arc::new(Mutex::new(None));
        let server = RadioInterfaceLayerRequestStream::from_channel(chan)
            .try_for_each(move |req| Self::handle_request(modem.clone(), client.clone(), req))
            .unwrap_or_else(|e| fx_log_err!("Error running {:?}", e));
        fasync::spawn(server);
    }

    async fn handle_request(
        modem: QmiModemPtr, mut client: ClientPtr, request: RadioInterfaceLayerRequest,
    ) -> Result<(), fidl::Error> {
        match request {
            RadioInterfaceLayerRequest::ConnectTransport { channel, responder } => {
                let mut lock = modem.lock();
                let status = lock.connect_transport(channel);
                fx_log_info!("Connecting the service to the transport driver: {}", status);
                responder.send(status)
            }
            RadioInterfaceLayerRequest::GetDeviceIdentity { responder } => {
                let mut client_lock = client.lock();

                if client_lock.is_none() {
                    fx_log_info!("Requested client connect.");
                    // TODO RIL Error type
                    let modem_lock = modem.lock();
                    let alloced_client = await!(modem_lock.create_client()).unwrap();
                    *client_lock = Some(alloced_client);
                }

                if let Some(ref client) = *client_lock {
                    let resp: QmiResult<DMS::GetDeviceSerialNumbersResp> =
                        await!(client.send_msg(DMS::GetDeviceSerialNumbersReq::new())).unwrap();
                    return responder.send(&resp.unwrap().imei);
                }
                responder.send("none")
            }
            RadioInterfaceLayerRequest::RadioPowerStatus { responder } => {
                let mut client_lock = client.lock();

                if client_lock.is_none() {
                    fx_log_info!("Requested client connect.");
                    // TODO RIL Error type
                    let modem_lock = modem.lock();
                    let alloced_client = await!(modem_lock.create_client()).unwrap();
                    *client_lock = Some(alloced_client);
                }

                if let Some(ref client) = *client_lock {
                    fx_log_info!("send serial request!");
                    let resp: DMS::GetOperatingModeResp =
                        await!(client.send_msg(DMS::GetOperatingModeReq::new())).unwrap().unwrap();
                    if (resp.operating_mode == 0x00) {
                        return responder.send(RadioPowerState::On);
                    } else {
                        return responder.send(RadioPowerState::Off);
                    }
                }
                responder.send(RadioPowerState::Off)
            }
        }
    }
}

fn main() -> Result<(), Error> {
    syslog::init_with_tags(&["ril-qmi"]).expect("Can't init logger");
    fx_log_info!("Starting ril-qmi...");

    let mut executor = fasync::Executor::new().context("Error creating executor")?;

    let modem = Arc::new(Mutex::new(QmiModem::new()));

    let server = ServicesServer::new()
        .add_service((RadioInterfaceLayerMarker::NAME, move |chan: fasync::Channel| {
            fx_log_info!("New client connecting to the Fuchsia RIL");
            FrilService::spawn(modem.clone(), chan)
        })).start()
        .context("Error starting QMI modem service")?;

    executor.run_singlethreaded(server)
}
