/*
 * Copyright 2008-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.hasor.land.node;
import io.netty.util.internal.ConcurrentSet;
import net.hasor.core.EventListener;
import net.hasor.core.Init;
import net.hasor.core.Inject;
import net.hasor.land.bootstrap.LandContext;
import net.hasor.land.domain.LandEvent;
import net.hasor.land.domain.ServerStatus;
import net.hasor.land.utils.TermUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
 * 当前服务器节点信息
 *
 * @version : 2016年09月10日
 * @author 赵永春 (zyc@hasor.net)
 */
public class ServerNode implements EventListener<Object>, Operation {
    protected     Logger         logger        = LoggerFactory.getLogger(getClass());
    @Inject
    private       LandContext    landContext   = null;
    private       List<NodeData> allNodes      = null; //所有服务器节点
    private       Set<String>    supporterVote = null; //支持者的选票
    //
    private final Object         lock          = new Object();
    private       ServerStatus   status        = null; //当前状态
    private       String         currentTerm   = null; //当前任期
    private       String         votedFor      = null; //得票候选人ID
    private       long           lastHeartbeat = 0;    //最后一次来自Leader的心跳时间
    //
    //
    //
    /** 当前条目ID(已递交，已生效) */
    public String getCurrentTerm() {
        return currentTerm;
    }
    /** 当前服务器的选票投给了谁 */
    public String getVotedFor() {
        return votedFor;
    }
    /** 当前服务器节点状态 */
    public ServerStatus getStatus() {
        return status;
    }
    /** 最后一次 Leader 发来的心跳时间 */
    public long getLastHeartbeat() {
        return lastHeartbeat;
    }
    /** 获取所有在线状态的节点 */
    public List<NodeData> getOnlineNodes() {
        return allNodes;
    }
    //
    //
    //
    @Init
    public void init() throws URISyntaxException {
        //
        this.currentTerm = "0";
        this.votedFor = null;
        this.status = ServerStatus.Follower;
        this.landContext.addVotedListener(this);
        this.landContext.addStatusListener(this);
        //
        // .添加节点
        this.allNodes = new ArrayList<NodeData>();
        Collection<String> serverIDs = this.landContext.getServerIDs();
        for (String serverID : serverIDs) {
            this.allNodes.add(new NodeData(serverID, this.landContext));
        }
        //
        this.supporterVote = new ConcurrentSet<String>();
    }
    //
    //
    //
    @Override
    public void onEvent(String event, Object eventData) throws Throwable {
        if (eventData == null) {
            return;
        }
        if (LandEvent.ServerStatus.equalsIgnoreCase(event)) {
            this.status = (ServerStatus) eventData;
        }
        if (LandEvent.VotedFor_Event.equalsIgnoreCase(event)) {
            this.votedFor = (String) eventData;
        }
    }
    public void lockRun(RunLock runnable) {
        synchronized (this.lock) {
            runnable.run(this);
        }
    }
    @Override
    public boolean testVote(String serverID) {
        return this.supporterVote.contains(serverID);
    }
    //
    //
    //
    /** Term 自增 */
    public void incrementAndGetTerm() {
        this.currentTerm = TermUtils.incrementAndGet(this.currentTerm);
    }
    /** Term 更新成比自己大的那个 */
    public boolean updateTermTo(String remoteTerm) {
        if (TermUtils.gtFirst(this.currentTerm, remoteTerm)) {
            this.currentTerm = remoteTerm;
            return true;
        }
        return false;
    }
    /** 更新最后一次收到 Leader 的心跳时间 */
    public void newLastLeaderHeartbeat() {
        this.lastHeartbeat = System.currentTimeMillis();
    }
    @Override
    public void applyVoted(String serverID, boolean voteGranted) {
        if (voteGranted) {
            this.supporterVote.add(serverID);
        } else {
            this.supporterVote.remove(serverID);
        }
    }
    @Override
    public void clearVoted() {
        this.supporterVote.clear();
    }
}