#include "manual_protect.h"
#include <math.h>
#include "define.h"
#include "collector-api.h"
#include "jsonct.h"
#include "microgridtopology.h"
#include "emsctrlProc.h"
#include "deviceLayer.h"
#include "discover.h"
#include "pub_fun.h"

static inline double dmin(double a, double b) { return a < b ? a : b; }
static inline double dmax(double a, double b) { return a > b ? a : b; }
static inline double dclamp(double v, double lo, double hi) { return v < lo ? lo : (v > hi ? hi : v); }

#define PRECHECK_OK    1
#define PRECHECK_FAIL  0

typedef struct {
    enum ENERGY_DIRECTION prev_direction;
} manual_protect_state_t;

manual_protect_state_t g_manual_protect_state = {ENERGY_DEFAULT};

static void manual_mode_data_reset(void)
{
    if (g_usercfg_variant.EnProtectReverse) {
        antiReflux(0, 0, 0, 0, 0, 0, 1);
        if (microgrid_ctrl.EnPhaseCtrl == 1) {
            antiReflux_A(0, 0, 0, 0, 0, 0, 1);
            antiReflux_B(0, 0, 0, 0, 0, 0, 1);
            antiReflux_C(0, 0, 0, 0, 0, 0, 1);
        }
    }
    if (g_usercfg_variant.EnProtectTransf == 1 || g_usercfg_variant.EnProtectTransf == 2) {
        xl_antiReflux(0, 0, 0, 0, 0, 0, 0, 1);
    }
    if (g_usercfg_variant.EnProtectTrasLV) {
        xl_LV_antiReflux(0, 0, 0, 0, 0, 0, 0, 1);
    }
    g_manual_protect_state.prev_direction = ENERGY_DEFAULT;
}

static inline int is_dc_microgrid(enum MODE_MICROGRID mode)
{
    return mode == MODE_MICROGRID_DC;
}

static inline int is_ac_microgrid(enum MODE_MICROGRID mode)
{
    return mode == MODE_MICROGRID_AC;
}

static inline int is_standard_cabinet(enum MODE_MICROGRID mode)
{
    return mode == MODE_MICROGRID_NONE;
}

typedef struct {
    enum MODE_MICROGRID mode;
    double user_set_actpower;   /* 用户设定 PCS 功率 */
    double user_set_pvpower;    /* 用户设定 PV 功率 */
    double discharge_limit;     /* 放电上限 > 0 */
    double charge_limit;        /* 充电下限 < 0 */
    double pv_max;              /* 光伏上限 */
    double actual_pcs_power;    /* PCS 实际功率 */
    double actual_pv_power;     /* PV 实际功率 */

    double grid_s;          /* 高压侧视在功率 S */
    double Pmlmax;          /* 变压器容量 */
    double grid_p;          /* 关口表有功 P */
    double max_demand;      /* 最大需量 */
    double grid_q;          /* 关口表无功 Q */
    double K1;              /* K1 原始值 */
    double demand_margin;   /* 需量回差 */
    double lv_grid_s;       /* 低压侧视在功率 S */
    double lv_grid_p;       /* 低压侧有功 P */
    double lv_grid_q;       /* 低压侧无功 Q */
    double PLVmlmax;        /* 低压变压器容量 */
    double K4;              /* K4 原始值 */

    double grid_pa;  /* 关口表 A 相有功功率 */
    double grid_pb;  /* 关口表 B 相有功功率 */
    double grid_pc;  /* 关口表 C 相有功功率 */
    double pcs_pa;   /* PCS A 相功率 */
    double pcs_pb;   /* PCS B 相功率 */
    double pcs_pc;   /* PCS C 相功率 */
} protect_ctx_t;

static inline int phase_reverse_enabled(const protect_ctx_t *ctx)
{
    return (is_dc_microgrid(ctx->mode) || is_ac_microgrid(ctx->mode)) && (microgrid_ctrl.EnPhaseCtrl != 0);
}

static double phase_antiReflux_limit(const protect_ctx_t *ctx, double reflux, double limit, double pcs_min)
{
    double safe_power_a = antiReflux_A(ctx->grid_pa, reflux / 3.0, 1, limit, pcs_min, ctx->pcs_pa, 0);
    double safe_power_b = antiReflux_B(ctx->grid_pb, reflux / 3.0, 1, limit, pcs_min, ctx->pcs_pb, 0);
    double safe_power_c = antiReflux_C(ctx->grid_pc, reflux / 3.0, 1, limit, pcs_min, ctx->pcs_pc, 0);
    return dmin(dmin(safe_power_a, safe_power_b), safe_power_c);
}

static const char *direction_str(enum ENERGY_DIRECTION dir)
{
    return dir == DISCHARGE_DIRECTION ? "discharge"
         : dir == CHARGE_DIRECTION    ? "charge"
         : "idle";
}

static int protect_precheck(cabinet_info_t *cab)
{
    if (g_usercfg_variant.ControlMode != EMS_MANUAL_PROTECT_MODE
        || (cab->ctrl_mode == EMS_MODE_ZC && cab->is_slave != 0)
        || dev_get_dev_tag_int(DEV_NO_GRID_MT, STATE_ONLINE) != 1
        || dev_get_dev_tag_int(DEV_NO_EMS, SYSTEM_STATUS) != 0)
        return PRECHECK_FAIL;
    return PRECHECK_OK;
}

static void protect_prepare(protect_ctx_t *ctx, cabinet_info_t *cab)
{
    ctx->user_set_actpower = dev_get_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER);
    ctx->mode     = cab->mode_microgrid;

    if (is_standard_cabinet(ctx->mode)) {
        ctx->user_set_pvpower = 0.0;

        ctx->discharge_limit = (double)g_usercfg_variant.cab_power;
        ctx->charge_limit    = -(double)g_usercfg_variant.cab_power;
        ctx->pv_max          = 0.0;

        int ems_num = get_discover_dev_num();
        if (ems_num < 1) {
            ems_num = 1;
        }

        double low_pcs_power = 0;
        int ems_num_low = 0, kvl_low_all = 0;
        get_total_low_point_info(&low_pcs_power, &ems_num_low, &kvl_low_all);
        if (ems_num_low < 1) {
            ems_num_low = ems_num;
        }

        ctx->actual_pcs_power = get_cur_power();
        ctx->actual_pv_power  = 0.0;

        ctx->grid_s = dev_get_dev_tag_float(DEV_NO_GRID_MT, APPARENT_POWER);
        ctx->Pmlmax   = (double)g_usercfg_variant.Pmlmax / ems_num;

        ctx->grid_p       = dev_get_dev_tag_float(DEV_NO_GRID_MT, METER_POWER);
        ctx->max_demand = (double)dev_get_dev_tag_int(DEV_NO_EMS, MAX_DEMAND) / ems_num;
        ctx->grid_q      = dev_get_dev_tag_float(DEV_NO_GRID_MT, REACTIVE_POWER);
        ctx->K1         = (double)g_usercfg_variant.K1;
        ctx->demand_margin     = (double)dev_get_dev_tag_int(DEV_NO_EMS, DEMAND_MARGIN);

        ctx->lv_grid_s   = dev_get_dev_tag_float(DEV_NO_TRAS_LV_MT, APPARENT_POWER);
        ctx->lv_grid_p = dev_get_dev_tag_float(DEV_NO_TRAS_LV_MT, METER_POWER);
        ctx->lv_grid_q   = dev_get_dev_tag_float(DEV_NO_TRAS_LV_MT, REACTIVE_POWER);
        ctx->PLVmlmax = (double)g_usercfg_variant.PLVmlmax / ems_num_low;
        ctx->K4       = (double)g_usercfg_variant.K4;

        ctx->grid_pa = dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.AphaseActivePower;
        ctx->grid_pb = dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.BphaseActivePower;
        ctx->grid_pc = dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.CphaseActivePower;
        ctx->pcs_pa = 0.0; ctx->pcs_pb = 0.0; ctx->pcs_pc = 0.0;
    } else {
        ctx->user_set_pvpower  = dev_get_dev_tag_float(DEV_NO_EMS, PH_P);

        if (is_dc_microgrid(ctx->mode) && microgrid_data.ems_num > 1) {
            ctx->discharge_limit = (double)micro_dc_equity_discharMax();
            ctx->charge_limit    = (double)micro_dc_equity_charMax();
        } else {
            ctx->discharge_limit = microgrid_ctrl.dischargeMaxPower;
            ctx->charge_limit    = microgrid_ctrl.chargeMaxPower;
        }
        ctx->pv_max          = microgrid_ctrl.pvMax;

        ctx->actual_pcs_power = microgrid_data.pcs_power;
        ctx->actual_pv_power  = microgrid_data.pv_power;

        ctx->grid_s = microgrid_data.grid_appower;
        ctx->Pmlmax   = microgrid_ctrl.Pmlmax;

        ctx->grid_p       = microgrid_data.grid_power;
        ctx->max_demand = (double)microgrid_ctrl.MaxDemand;
        ctx->grid_q      = microgrid_data.grid_repower;
        ctx->K1         = (double)microgrid_ctrl.K1;
        ctx->demand_margin     = microgrid_ctrl.PmlmaxDiff;

        ctx->lv_grid_s   = microgrid_data.grid_lv_appower;
        ctx->lv_grid_p = dev_info_all.meter_grid_lv.meter_grid_param[0].info.meter_grid_data.act_power;
        ctx->lv_grid_q   = dev_info_all.meter_grid_lv.meter_grid_param[0].info.meter_grid_data.rea_power;
        ctx->PLVmlmax = (double)microgrid_ctrl.PLVmlmax;
        ctx->K4       = (double)microgrid_ctrl.k4;

        ctx->grid_pa = dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.AphaseActivePower;
        ctx->grid_pb = dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.BphaseActivePower;
        ctx->grid_pc = dev_info_all.meter_grid.meter_grid_param[0].info.meter_grid_data.CphaseActivePower;
        ctx->pcs_pa = microgrid_data.PhasePower[PHASE_A];
        ctx->pcs_pb = microgrid_data.PhasePower[PHASE_B];
        ctx->pcs_pc = microgrid_data.PhasePower[PHASE_C];
    }
}

static void mppt_exp_power_set_by_count(double pv_final)
{
    int cab_num = dev_info_all.cabinet_info.num;
    int total_mppt = 0;

    for (int i = 0; i < cab_num; i++) {
        total_mppt += dev_info_all.cabinet_info.cabinet_inside[i]->mppt.num;
    }

    if (total_mppt <= 0) {
        ems_syslog(LOG_DEBUG, "[manual_protect] mppt dist: no mppt device, cab_num=%d pv_final=%.2f",
                   cab_num, pv_final);

        for (int i = 0; i < cab_num; i++) {
            dev_info_all.cabinet_info.cabinet_inside[i]->cab_ctrl.mppt_exp_power = 0;
        }
        return;
    }

    for (int i = 0; i < cab_num; i++) {
        cabinet_inside_t *cab = dev_info_all.cabinet_info.cabinet_inside[i];

        cab->cab_ctrl.mppt_exp_power = pv_final * cab->mppt.num / total_mppt;

        ems_syslog(LOG_DEBUG, "[manual_protect] mppt dist: cab=%s mppt_num=%d total_mppt=%d exp_power=%.2f",
                   cab->no, cab->mppt.num, total_mppt, cab->cab_ctrl.mppt_exp_power);
    }
}

static void ac_manual_set_dev_power(double pv_final)
{
    dev_info_all_t *var = get_dev_info_all_var();

    for (int i = 0; i < var->cabinet_info.num; i++) {
        cabinet_inside_t *cab = var->cabinet_info.cabinet_inside[i];
        double p_exp = atomic_load(&cab->cab_ctrl.pcs_exp_power);
        double p = p_exp;

        if (microgrid_ctrl.en_bms_power_limit) {
            if (p > 0) {
                p = dmin(p, cab->cab_ctrl.pcs_discharge_max_actual);
            } else if (p < 0) {
                p = dmax(p, cab->cab_ctrl.pcs_charge_max_actual);
            }
        }

        dev_set_dev_tag_float(cab->no, SET_ACT_POWER, p);

        ems_syslog(LOG_DEBUG, "[manual_protect] ac pcs: cab=%s pcs_exp=%.2f pcs_set=%.2f bms_limit=%d",
                   cab->no, p_exp, p, microgrid_ctrl.en_bms_power_limit);
    }

    double sum_scale = 0;
    for (int i = 0; i < var->pv.num; i++) {
        if (var->pv.pv_param[i].info.pv_data.on_line) {
            sum_scale += var->pv.pv_param[i].info.pv_cfg.scale;
        }
    }

    for (int i = 0; i < var->pv.num; i++) {
        struct _pv_t *pv = &var->pv.pv_param[i];
        double scale = pv->info.pv_cfg.scale;
        double p = 0.0;

        if (sum_scale > 0 && pv->info.pv_data.on_line) {
            p = pv_final * scale / sum_scale;
            p = dclamp(p, 0.0, microgrid_ctrl.pvMax * scale);
        }

        atomic_store(&pv->info.pv_ctrl.power_set, p);
        pe_set_power(pv->no, p);

        ems_syslog(LOG_DEBUG, "[manual_protect] ac pv: pv=%s scale=%.2f sum_scale=%.2f online=%d power_set=%.2f",
                   pv->no, scale, sum_scale, pv->info.pv_data.on_line, p);
    }
}

static void protect_system_abnormal(enum MODE_MICROGRID mode)
{
    if (dev_get_dev_tag_int(DEV_NO_EMS, SYSTEM_STATUS) == 0) {
        return;
    }

    ems_syslog(LOG_DEBUG, "[manual_protect] system abnormal, keep PCS/PV at 0");

    if (is_standard_cabinet(mode)) {
        lc_power_info_t info = {0};
        set_lc_power(info);
    } else if (is_dc_microgrid(mode)) {
        pcs_stop();
        mppt_stop();
    } else {
        adjust_to_target(0, 0);
        ac_set_power();
        ac_manual_set_dev_power(0);
    }
}

static void protect_apply(enum MODE_MICROGRID mode, double pcs_final, double pv_final)
{
    if (is_standard_cabinet(mode)) {
        lc_power_info_t info = {0};
        info.active_power = pcs_final;
        set_lc_power(info);
    } else if (is_dc_microgrid(mode)) {
        double pcs_local = pcs_final;
        if (microgrid_data.ems_num > 1) {
            pcs_local = micro_dc_equity(pcs_final);
            micro_broadcast_data();
        }
        microgrid_ctrl.pcs_exp_power = pcs_local;
        traverse_cab_dev_func(cabinet_pcs_exp_power_set);
        PCS_set_power(pcs_local, 0);

        mppt_exp_power_set_by_count(pv_final);
        MPPT_set_power(pv_final, 0);
    } else {
        accord_soc_cal_supportpower(microgrid_ctrl.SOC_min_combin, microgrid_ctrl.SOC_max_combin);
        adjust_to_target(pv_final, pcs_final);
        ac_set_power();
        ac_manual_set_dev_power(pv_final);
    }
}

static void protect_discharge(protect_ctx_t *ctx, double *pcs, double *pv)
{
    double pcs_final = ctx->user_set_actpower;
    double pv_final  = 0.0;

    if (g_usercfg_variant.EnProtectReverse) {
        double limit  = ctx->discharge_limit;
        double output = ctx->actual_pcs_power;
        if (is_ac_microgrid(ctx->mode)) {
            limit  += ctx->pv_max;
            output += ctx->actual_pv_power;
        }

        double safe_power = 0.0;
        if (phase_reverse_enabled(ctx)) {
            double safe_power_per_phase = phase_antiReflux_limit(ctx, (double)g_usercfg_variant.Pset, ctx->discharge_limit, 0);
            safe_power = 3.0 * safe_power_per_phase;
            ems_syslog(LOG_DEBUG,
                       "[manual_protect] discharge: EnPhaseCtrl=%d pa=%.2f pb=%.2f pc=%.2f safe_power_per_phase=%.2f safe_power=%.2f",
                       microgrid_ctrl.EnPhaseCtrl, ctx->pcs_pa, ctx->pcs_pb, ctx->pcs_pc, safe_power_per_phase, safe_power);
        } else {
            safe_power = antiReflux(ctx->grid_p, (double)g_usercfg_variant.Pset, 1, limit, 0, output, 0);
            ems_syslog(LOG_DEBUG, "[manual_protect] discharge: safe_power=%.2f", safe_power);
        }

        if (is_ac_microgrid(ctx->mode)) {
            pv_final  = dclamp(ctx->user_set_pvpower, 0.0, safe_power);
            pcs_final = dmin(dmin(ctx->user_set_actpower, safe_power - ctx->actual_pv_power), ctx->discharge_limit);
        } else {
            pcs_final = dmin(dmin(ctx->user_set_actpower, safe_power), ctx->discharge_limit);
            pv_final  = dclamp(ctx->user_set_pvpower, 0.0, pcs_final + fabs(ctx->charge_limit));
        }
    } else {
        pcs_final = dmin(ctx->user_set_actpower, ctx->discharge_limit);
        if (is_ac_microgrid(ctx->mode)) {
            pv_final = ctx->user_set_pvpower;
        } else {
            pv_final = dclamp(ctx->user_set_pvpower, 0.0, pcs_final + fabs(ctx->charge_limit));
        }
    }

    *pcs = dmax(pcs_final, 0.0);
    *pv  = dclamp(pv_final, 0.0, ctx->pv_max);
}

static void protect_charge(protect_ctx_t *ctx, double *pcs, double *pv)
{
    double safe_power_hv = ctx->user_set_actpower;
    double safe_power_lv = ctx->user_set_actpower;
    active_power_result_t ap = {0};

    if (g_usercfg_variant.EnProtectTransf == 1) {
        calc_active_power_limits(&microgrid_ctrl.rea_flt_hv, ctx->Pmlmax, ctx->Pmlmax * ctx->K1 / 100.0, ctx->grid_q, &ap);
        safe_power_hv = xl_antiReflux(ctx->grid_p, ap.limit, 1, 0, ctx->charge_limit, ctx->actual_pcs_power, ap.target, 0);
        ems_syslog(LOG_DEBUG, "[manual_protect] charge HV(transf): limit=%.2f target=%.2f safe_hv=%.2f",
                   ap.limit, ap.target, safe_power_hv);
    } else if (g_usercfg_variant.EnProtectTransf == 2) {
        double max_demand = apply_pmlmax_activepower_limit(ctx->max_demand, ctx->Pmlmax, (int)ctx->K1, ctx->grid_q);
        double _max_demand = max_demand - ctx->demand_margin;
        _max_demand = _max_demand > 0 ? _max_demand : 0;
        safe_power_hv = xl_antiReflux(ctx->grid_p, max_demand, 1, 0, ctx->charge_limit, ctx->actual_pcs_power, _max_demand, 0);
        ems_syslog(LOG_DEBUG, "[manual_protect] charge HV(demand): max_demand=%.2f _max_demand=%.2f safe_hv=%.2f",
                   max_demand, _max_demand, safe_power_hv);
    }

    if (g_usercfg_variant.EnProtectTrasLV) {
        calc_active_power_limits(&microgrid_ctrl.rea_flt_lv, ctx->PLVmlmax, ctx->PLVmlmax * ctx->K4 / 100.0, ctx->lv_grid_q, &ap);
        safe_power_lv = xl_LV_antiReflux(ctx->lv_grid_p, ap.limit, 1, 0, ctx->charge_limit, ctx->actual_pcs_power, ap.target, 0);
        ems_syslog(LOG_DEBUG, "[manual_protect] charge LV: limit=%.2f target=%.2f safe_lv=%.2f",
                   ap.limit, ap.target, safe_power_lv);
    }

    double pcs_final = dmax(dmax(ctx->user_set_actpower, safe_power_hv), safe_power_lv);
    pcs_final = dmax(pcs_final, ctx->charge_limit);

    double pv_final = 0.0;
    if (is_dc_microgrid(ctx->mode)) {
        pv_final = dclamp(ctx->user_set_pvpower, 0.0, fabs(ctx->charge_limit) - fabs(pcs_final));
    } else {
        pv_final = ctx->user_set_pvpower;
    }

    *pcs = dmin(pcs_final, 0.0);
    *pv  = dclamp(pv_final, 0.0, ctx->pv_max);
}

static void protect_idle(protect_ctx_t *ctx, double *pcs, double *pv)
{
    double pv_final = 0.0;
    if (is_dc_microgrid(ctx->mode)) {
        pv_final = dclamp(ctx->user_set_pvpower, 0.0, fabs(ctx->charge_limit));
    } else if (is_ac_microgrid(ctx->mode)) {
        pv_final = ctx->user_set_pvpower;
        if (g_usercfg_variant.EnProtectReverse) {
            double limit  = ctx->pv_max;
            double output = ctx->actual_pv_power;
            double safe_power = antiReflux(ctx->grid_p, (double)g_usercfg_variant.Pset, 1, limit, 0, output, 0);
            pv_final = dclamp(ctx->user_set_pvpower, 0.0, safe_power);
            ems_syslog(LOG_DEBUG, "[manual_protect] idle AC: safe_power=%.2f pv_final=%.2f",
                       safe_power, pv_final);
        }
    }

    *pcs = ctx->user_set_actpower;
    *pv  = dclamp(pv_final, 0.0, ctx->pv_max);
}

void manual_mode_power_protect(void)
{
    cabinet_info_t *cab = get_cabinet_info();

    protect_system_abnormal(cab->mode_microgrid);

    if (protect_precheck(cab) == PRECHECK_FAIL) {
        ems_syslog(LOG_DEBUG,
                   "[manual_protect] precheck fail, skip (mode=%d, ctrl=%d, slave=%d, sys_status=%d)",
                   g_usercfg_variant.ControlMode, cab->ctrl_mode, cab->is_slave,
                   dev_get_dev_tag_int(DEV_NO_EMS, SYSTEM_STATUS));
        return;
    }

    protect_ctx_t ctx = {0};
    protect_prepare(&ctx, cab);

    enum ENERGY_DIRECTION direction = IS_DISCHARGE(ctx.user_set_actpower) ? DISCHARGE_DIRECTION
                                      : (IS_CHARGE(ctx.user_set_actpower) ? CHARGE_DIRECTION : ENERGY_DEFAULT);
    if (direction != g_manual_protect_state.prev_direction) {
        ems_syslog(LOG_NOTICE,
                   "[manual_protect] direction changed: prev=%s cur=%s, reset algorithm",
                   direction_str(g_manual_protect_state.prev_direction), direction_str(direction));
        manual_mode_data_reset();
    }

    ems_syslog(LOG_DEBUG,
               "[manual_protect] prepare: mode=%d; user_pcs=%.2f; user_pv=%.2f; actual_pcs=%.2f; actual_pv=%.2f; grid_p/s/q=%.2f/%.2f/%.2f; "
               "Pmlmax=%.2f; max_demand=%.2f; K1=%.2f; demand_margin=%.2f; lv_p/s/q=%.2f/%.2f/%.2f; "
               "PLVmlmax=%.2f; K4=%.2f; dis_limit=%.2f; chg_limit=%.2f; pv_max=%.2f; grid_a/b/c=%.2f/%.2f/%.2f; phase_rev=%d",
               ctx.mode, ctx.user_set_actpower, ctx.user_set_pvpower,
               ctx.actual_pcs_power, ctx.actual_pv_power,
               ctx.grid_p, ctx.grid_s, ctx.grid_q,
               ctx.Pmlmax, ctx.max_demand, ctx.K1, ctx.demand_margin,
               ctx.lv_grid_p, ctx.lv_grid_s, ctx.lv_grid_q,
               ctx.PLVmlmax, ctx.K4,
               ctx.discharge_limit, ctx.charge_limit, ctx.pv_max,
               ctx.grid_pa, ctx.grid_pb, ctx.grid_pc,
               phase_reverse_enabled(&ctx));

    double pcs_final = 0.0, pv_final = 0.0;
    if (direction == DISCHARGE_DIRECTION) {
        protect_discharge(&ctx, &pcs_final, &pv_final);
    } else if (direction == CHARGE_DIRECTION) {
        protect_charge(&ctx, &pcs_final, &pv_final);
    } else {
        protect_idle(&ctx, &pcs_final, &pv_final);
    }

    ems_syslog(LOG_NOTICE,
               "[manual_protect] result: dir=%s pcs_final=%.2f pv_final=%.2f mode=%d",
               direction_str(direction),
               pcs_final, pv_final, ctx.mode);

    protect_apply(ctx.mode, pcs_final, pv_final);

    g_manual_protect_state.prev_direction = direction;
}
