package org.skywalking.apm.agent.core.context;

import java.io.Serializable;
import java.util.List;
import org.skywalking.apm.agent.core.context.ids.DistributedTraceId;
import org.skywalking.apm.agent.core.context.ids.ID;
import org.skywalking.apm.agent.core.context.ids.PropagatedTraceId;
import org.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.skywalking.apm.agent.core.dictionary.DictionaryUtil;
import org.skywalking.apm.util.StringUtil;

/**
 * {@link ContextCarrier} is a data carrier of {@link TracingContext}.
 * It holds the snapshot (current state) of {@link TracingContext}.
 * <p>
 * Created by wusheng on 2017/2/17.
 */
public class ContextCarrier implements Serializable {
    /**
     * {@link TraceSegment#traceSegmentId}
     */
    private ID traceSegmentId;

    private int spanId = -1;

    private int parentApplicationInstanceId = DictionaryUtil.nullValue();

    private int entryApplicationInstanceId = DictionaryUtil.nullValue();

    private String peerHost;

    private String entryOperationName;

    private String parentOperationName;

    /**
     * {@link DistributedTraceId}
     */
    private DistributedTraceId primaryDistributedTraceId;

    /**
     * Serialize this {@link ContextCarrier} to a {@link String},
     * with '|' split.
     *
     * @return the serialization string.
     */
    public String serialize() {
        if (this.isValid()) {
            return StringUtil.join('|',
                this.getTraceSegmentId().toBase64(),
                this.getSpanId() + "",
                this.getParentApplicationInstanceId() + "",
                this.getEntryApplicationInstanceId() + "",
                this.getPeerHost(),
                this.getEntryOperationName(),
                this.getParentOperationName(),
                this.getPrimaryDistributedTraceId().toBase64());
        } else {
            return "";
        }
    }

    /**
     * Initialize fields with the given text.
     *
     * @param text carries {@link #traceSegmentId} and {@link #spanId}, with '|' split.
     */
    public ContextCarrier deserialize(String text) {
        if (text != null) {
            String[] parts = text.split("\\|", 8);
            if (parts.length == 8) {
                try {
                    this.traceSegmentId = new ID(parts[0]);
                    this.spanId = Integer.parseInt(parts[1]);
                    this.parentApplicationInstanceId = Integer.parseInt(parts[2]);
                    this.entryApplicationInstanceId = Integer.parseInt(parts[3]);
                    this.peerHost = parts[4];
                    this.entryOperationName = parts[5];
                    this.parentOperationName = parts[6];
                    this.primaryDistributedTraceId = new PropagatedTraceId(parts[7]);
                } catch (NumberFormatException e) {

                }
            }
        }
        return this;
    }

    /**
     * Make sure this {@link ContextCarrier} has been initialized.
     *
     * @return true for unbroken {@link ContextCarrier} or no-initialized. Otherwise, false;
     */
    public boolean isValid() {
        return traceSegmentId != null
            && getSpanId() > -1
            && parentApplicationInstanceId != DictionaryUtil.nullValue()
            && entryApplicationInstanceId != DictionaryUtil.nullValue()
            && !StringUtil.isEmpty(peerHost)
            && !StringUtil.isEmpty(entryOperationName)
            && !StringUtil.isEmpty(parentOperationName)
            && primaryDistributedTraceId != null;
    }

    public String getEntryOperationName() {
        return entryOperationName;
    }

    void setEntryOperationName(String entryOperationName) {
        this.entryOperationName = '#' + entryOperationName;
    }

    void setEntryOperationId(int entryOperationId) {
        this.entryOperationName = entryOperationId + "";
    }

    void setParentOperationName(String parentOperationName) {
        this.parentOperationName = '#' + parentOperationName;
    }

    void setParentOperationId(int parentOperationId) {
        this.parentOperationName = parentOperationId + "";
    }

    public ID getTraceSegmentId() {
        return traceSegmentId;
    }

    public int getSpanId() {
        return spanId;
    }

    void setTraceSegmentId(ID traceSegmentId) {
        this.traceSegmentId = traceSegmentId;
    }

    void setSpanId(int spanId) {
        this.spanId = spanId;
    }

    public int getParentApplicationInstanceId() {
        return parentApplicationInstanceId;
    }

    void setParentApplicationInstanceId(int parentApplicationInstanceId) {
        this.parentApplicationInstanceId = parentApplicationInstanceId;
    }

    public String getPeerHost() {
        return peerHost;
    }

    void setPeerHost(String peerHost) {
        this.peerHost = '#' + peerHost;
    }

    void setPeerId(int peerId) {
        this.peerHost = peerId + "";
    }

    public DistributedTraceId getDistributedTraceId() {
        return primaryDistributedTraceId;
    }

    public void setDistributedTraceIds(List<DistributedTraceId> distributedTraceIds) {
        this.primaryDistributedTraceId = distributedTraceIds.get(0);
    }

    private DistributedTraceId getPrimaryDistributedTraceId() {
        return primaryDistributedTraceId;
    }

    public String getParentOperationName() {
        return parentOperationName;
    }

    public int getEntryApplicationInstanceId() {
        return entryApplicationInstanceId;
    }

    public void setEntryApplicationInstanceId(int entryApplicationInstanceId) {
        this.entryApplicationInstanceId = entryApplicationInstanceId;
    }

}

@@ -799,252 +799,919 @@
     
-private int spanId = -1;%0A%0A    private int parentApplicationInstanceId = DictionaryUtil.nullValue();%0A%0A    private int entryApplicationInstanceId = DictionaryUtil.nullValue();%0A%0A    private String peerHost;%0A%0A    private String entryOperationName;%0A
+/**%0A     * id of parent span.%0A     * It is unique in parent trace segment.%0A     */%0A    private int spanId = -1;%0A%0A    /**%0A     * id of parent application instance, it's the id assigned by collector.%0A     */%0A    private int parentApplicationInstanceId = DictionaryUtil.nullValue();%0A%0A    /**%0A     * id of first application instance in this distributed trace, it's the id assigned by collector.%0A     */%0A    private int entryApplicationInstanceId = DictionaryUtil.nullValue();%0A%0A    /**%0A     * peer(ipv4/ipv6/hostname + port) of the server, from client side.%0A     */%0A    private String peerHost;%0A%0A    /**%0A     * Operation/Service name of the first one in this distributed trace.%0A     * This name may be compressed to an integer.%0A     */%0A    private String entryOperationName;%0A%0A    /**%0A     * Operation/Service name of the parent one in this distributed trace.%0A     * This name may be compressed to an integer.%0A     */
 %0A   
@@ -1789,16 +1789,39 @@
 TraceId%7D
+, also known as TraceId
 %0A     */

Update ContextCarrier.java