/*
 * Copyright (C) 2016-2022 ActionTech.
 * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
 */

package com.actiontech.dble.backend.mysql.nio.handler.query.impl.manager;

import com.actiontech.dble.backend.mysql.nio.handler.query.BaseDMLHandler;
import com.actiontech.dble.backend.mysql.nio.handler.util.HandlerTool;
import com.actiontech.dble.net.Session;
import com.actiontech.dble.net.mysql.FieldPacket;
import com.actiontech.dble.net.mysql.RowDataPacket;
import com.actiontech.dble.net.service.AbstractService;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.FieldTypes;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.util.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * if the Item is Item_sum,then theItem must be generated in GroupBy.Otherwise,calc by middle-ware
 */
public class ManagerSendMakeHandler extends BaseDMLHandler {

    private final ReentrantLock lock;

    private List<Item> selects;
    private List<Field> sourceFields;
    private List<Item> selItems;
    private String tableAlias;
    private String table;
    private String schema;

    public ManagerSendMakeHandler(long id, Session session, List<Item> selects, String schema, String table, String tableAlias) {
        super(id, session);
        lock = new ReentrantLock();
        this.selects = selects;
        this.selItems = new ArrayList<>();
        this.schema = schema;
        this.table = table;
        this.tableAlias = tableAlias;
    }

    @Override
    public HandlerType type() {
        return HandlerType.MANAGER_SENDMAKER;
    }

    @Override
    public void fieldEofResponse(byte[] headerNull, List<byte[]> fieldsNull, List<FieldPacket> fieldPackets,
                                 byte[] eofNull, boolean isLeft, @NotNull AbstractService service) {
        lock.lock();
        try {
            session.setHandlerStart(this);
            if (terminate.get())
                return;
            this.fieldPackets = fieldPackets;
            this.sourceFields = HandlerTool.createFields(this.fieldPackets);
            for (Item sel : selects) {
                Item tmpItem = HandlerTool.createManagerItem(sel, this.sourceFields, 0, isAllPushDown(), type());
                tmpItem.setItemName(sel.getItemName());
                String selAlias = sel.getAlias();
                if (selAlias != null) {
                    // remove the added tmp FNAF
                    selAlias = StringUtil.removeApostropheOrBackQuote(selAlias);
                    if (StringUtils.indexOf(selAlias, Item.FNAF) == 0)
                        selAlias = StringUtils.substring(selAlias, Item.FNAF.length());
                }
                tmpItem = HandlerTool.createRefItem(tmpItem, schema, table, tableAlias, selAlias);
                this.selItems.add(tmpItem);
            }
            List<FieldPacket> newFieldPackets = new ArrayList<>();
            for (Item selItem : this.selItems) {
                FieldPacket tmpFp = new FieldPacket();
                selItem.makeField(tmpFp);
                /* Keep things compatible for old clients */
                if (tmpFp.getType() == FieldTypes.MYSQL_TYPE_VARCHAR.numberValue())
                    tmpFp.setType(FieldTypes.MYSQL_TYPE_VAR_STRING.numberValue());
                newFieldPackets.add(tmpFp);
            }
            nextHandler.fieldEofResponse(null, null, newFieldPackets, null, this.isLeft, service);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean rowResponse(byte[] rowNull, RowDataPacket rowPacket, boolean isLeft, @NotNull AbstractService service) {
        lock.lock();
        try {
            if (terminate.get())
                return true;
            HandlerTool.initFields(sourceFields, rowPacket.fieldValues);
            RowDataPacket newRp = new RowDataPacket(selItems.size());
            for (Item selItem : selItems) {
                byte[] b = selItem.getRowPacketByte();
                newRp.add(b);
            }
            nextHandler.rowResponse(null, newRp, this.isLeft, service);
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void rowEofResponse(byte[] eof, boolean isLeft, @NotNull AbstractService service) {
        lock.lock();
        try {
            if (terminate.get())
                return;
            session.setHandlerEnd(this);
            nextHandler.rowEofResponse(eof, this.isLeft, service);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void onTerminate() {
    }


}
