#include "lip/app/ptp/lip_ptp_cfg_defs.h"
#if LIP_PTP_ENABLE
#include "lip_ptp_master_sync.h"
#include "lip/app/ptp/sync/lip_ptp_site_sync.h"
#include "lip/app/ptp/lip_ptp.h"
#include "lip/app/ptp/misc/lip_ptp_tstmp_ops.h"

static void f_send_mst_sync(t_lip_ptp_inst_ctx *inst) {
    t_lip_ptp_master_sync_ctx *ctx = &inst->master;
    t_lip_ptp_port_md_sync_info sync_info;

    t_lip_ptp_tstmp local_time;
    lip_ptp_get_local_time(&local_time);
    t_lip_ptp_tstmp master_time = local_time;
    /* 10.2.9.2.1 setPSSyncCMSS (gmRateRatio)  */

    /* b) preciseOriginTimestamp = masterTime. без мастера = localTime */
    f_host_tstmp_to_pkt(&master_time, &sync_info.preciseOriginTimestamp);

    /* c) fupCorrection */
    /** @todo также добавление gmRateRatio (currentTime – localTime), где это разница текущего времени и времени получения последнего masterTime */
    sync_info.fupCorrection = NTOH64(master_time.fract_ns);
    /* f */
    sync_info.logMessageInterval = ctx->tx_log_interval;
    /* g для master это должно быть время последнего получения masterTime, без мастера - текущее время  */
    sync_info.upstreamTxTime = local_time;

    sync_info.rateRatio = inst->gm_stats.rateRatio;
    sync_info.rateRatioValid = true;
    memset(&sync_info.lastChange, 0, sizeof(sync_info.lastChange));

    lip_ptp_site_sync_send_master(inst, &sync_info);
    lip_printf(LIP_LOG_MODULE_PTP, LIP_LOG_LVL_DEBUG_MEDIUM, 0, "lip ptp: send master sync time: " LIP_PTP_PRINT_TSTMP_FMT "\n",
               LIP_PTP_PRINT_TSTMP_VAL(local_time));
}


void lip_ptp_master_sync_init(t_lip_ptp_inst_ctx *inst) {
    memset(&inst->master, 0, sizeof(t_lip_ptp_master_sync_ctx));
}


void lip_ptp_master_sync_pull(t_lip_ptp_inst_ctx *inst) {
    t_lip_ptp_master_sync_ctx *ctx = &inst->master;
    if (ctx->state != LIP_PTP_MASTER_SYNC_SEND_STATE_OFF) {
        if (ltimer_expired(&ctx->tx_interval_tmr)) {
            if (ctx->state == LIP_PTP_MASTER_SYNC_SEND_STATE_ACTIVE) {
                ltimer_restart(&ctx->tx_interval_tmr);
                f_send_mst_sync(inst);
            } else if (ctx->state == LIP_PTP_MASTER_SYNC_SEND_STATE_INIT) {
                ctx->state = LIP_PTP_MASTER_SYNC_SEND_STATE_ACTIVE;
                inst->gm_stats.flags |= LIP_PTP_GM_STATS_FLAG_SELF_GM;
                lip_ptp_set_log_interval_tmr(&ctx->tx_interval_tmr, ctx->tx_log_interval, 1);
                /** @todo в случае внешнего источника master clock, rateRatio нужно обновлять разницой между
                          частотой мастера и localClock */
                inst->gm_stats.rateRatio = 1.;
                inst->gm_stats.flags |= LIP_PTP_GM_STATS_FLAG_RATE_VALID;
            }
        }
    }
}



void lip_ptp_master_sync_send_enable(t_lip_ptp_inst_ctx *inst, bool en) {
    t_lip_ptp_master_sync_ctx *ctx = &inst->master;
    bool is_en = ctx->state != LIP_PTP_MASTER_SYNC_SEND_STATE_OFF;
    if (en != is_en) {
        if (en) {
            ctx->state = LIP_PTP_MASTER_SYNC_SEND_STATE_INIT;
            ltimer_set_ms(&ctx->tx_interval_tmr, LIP_PTP_SYNC_GM_SEND_WAIT_TIME);
        } else {
            ctx->state = LIP_PTP_MASTER_SYNC_SEND_STATE_OFF;
            inst->gm_stats.flags &= ~LIP_PTP_GM_STATS_FLAG_SELF_GM;
        }
    }
}




#endif
