/*
 *
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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 org.apache.flex.compiler.internal.embedding.transcoders;

import java.util.Collection;
import java.util.EnumSet;
import java.util.Map;

import org.apache.flex.compiler.constants.IASKeywordConstants;
import org.apache.flex.compiler.constants.INamespaceConstants;
import org.apache.flex.compiler.internal.embedding.EmbedData;
import org.apache.flex.compiler.internal.parsing.as.ASToken;
import org.apache.flex.compiler.internal.parsing.as.ASTokenTypes;
import org.apache.flex.compiler.internal.semantics.PostProcessStep;
import org.apache.flex.compiler.internal.tree.as.BinaryOperatorNodeBase;
import org.apache.flex.compiler.internal.tree.as.ClassNode;
import org.apache.flex.compiler.internal.tree.as.FileNode;
import org.apache.flex.compiler.internal.tree.as.FunctionCallNode;
import org.apache.flex.compiler.internal.tree.as.FunctionNode;
import org.apache.flex.compiler.internal.tree.as.IdentifierNode;
import org.apache.flex.compiler.internal.tree.as.ImportNode;
import org.apache.flex.compiler.internal.tree.as.LanguageIdentifierNode;
import org.apache.flex.compiler.internal.tree.as.NamespaceIdentifierNode;
import org.apache.flex.compiler.internal.tree.as.PackageNode;
import org.apache.flex.compiler.internal.tree.as.ScopedBlockNode;
import org.apache.flex.compiler.internal.workspaces.Workspace;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.swf.tags.ICharacterTag;
import org.apache.flex.swf.tags.ITag;

/**
 * Handle the embedding of PBJ files
 */
public class PBJTranscoder extends DataTranscoder
{
    /**
     * Constructor.
     * 
     * @param data The embedding data.
     * @param workspace The workspace.
     */
    public PBJTranscoder(EmbedData data, Workspace workspace)
    {
        super(data, workspace);
    }

    @Override
    protected Map<String, ICharacterTag> doTranscode(Collection<ITag> tags, Collection<ICompilerProblem> problems)
    {
        // set the symbol name to be the ByteArray embed asset, not the wrapper qname
        String symbolName = data.getQName() + byteArrayNamePostfix;
        return doTranscode(symbolName, tags, problems);
    }

    @Override
    public FileNode buildAST(Collection<ICompilerProblem> problems, String filename)
    {
        FileNode fileNode = new FileNode(workspace, filename);
        PackageNode packageNode = new PackageNode(new IdentifierNode(""), null);
        fileNode.addItem(packageNode);

        ScopedBlockNode packageContents = packageNode.getScopedNode();
        ImportNode importNode = ImportNode.buildImportNode(getBaseClassQName());
        packageContents.addItem(importNode);
        importNode = ImportNode.buildImportNode("mx.core.IFlexAsset");
        packageContents.addItem(importNode);
        importNode = ImportNode.buildImportNode("flash.utils.ByteArray");
        packageContents.addItem(importNode);
        importNode = ImportNode.buildImportNode("flash.display.Shader");
        packageContents.addItem(importNode);

        // generate the byte array class name
        String byteArrayClassName = data.getQName() + byteArrayNamePostfix;
        ClassNode classNodeByteArray = new ClassNode(new IdentifierNode(byteArrayClassName));
        classNodeByteArray.setBaseClass(new IdentifierNode(getBaseClassName()));
        classNodeByteArray.setNamespace(new NamespaceIdentifierNode(INamespaceConstants.public_));
        packageContents.addItem(classNodeByteArray);

        // generate the pbj class name
        String pbjClassName = data.getQName();
        ClassNode classNodePbj = new ClassNode(new IdentifierNode(pbjClassName));
        classNodePbj.setBaseClass(new IdentifierNode("Shader"));
        classNodePbj.addInterface(new IdentifierNode("IFlexAsset"));
        classNodePbj.setNamespace(new NamespaceIdentifierNode(INamespaceConstants.public_));
        packageContents.addItem(classNodePbj);

        // build the constructor
        IdentifierNode constructorNameNode = new IdentifierNode(pbjClassName);
        constructorNameNode.setReferenceValue(classNodePbj.getDefinition());
        FunctionNode constructorNode = new FunctionNode(null, constructorNameNode);
        constructorNode.setNamespace(new NamespaceIdentifierNode(INamespaceConstants.public_));
        ScopedBlockNode constructorContents = constructorNode.getScopedNode();

        // generate: super();
        FunctionCallNode superCall = new FunctionCallNode(LanguageIdentifierNode.buildSuper());
        constructorContents.addItem(superCall);

        // generate: byteCode = new EmbedTest_sphereClassByteArray();
        ASToken newToken = new ASToken(ASTokenTypes.TOKEN_KEYWORD_NEW, -1, -1, -1, -1, IASKeywordConstants.NEW);
        FunctionCallNode newCall = new FunctionCallNode(newToken, new IdentifierNode(byteArrayClassName));
        ASToken assignToken = new ASToken(ASTokenTypes.TOKEN_OPERATOR_ASSIGNMENT, -1, -1, -1, -1, "=");
        BinaryOperatorNodeBase assignment = BinaryOperatorNodeBase.create(assignToken, new IdentifierNode("byteCode"), newCall);
        constructorContents.addItem(assignment);

        classNodePbj.getScopedNode().addItem(constructorNode);

        fileNode.runPostProcess(EnumSet.of(PostProcessStep.POPULATE_SCOPE));

        return fileNode;
    }
}
