/*
 * Copyright 2025 Antmicro
 *
 * 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 com.antmicro.girdl.data.rdl.parser.ast;

import com.antmicro.girdl.data.rdl.Location;
import com.antmicro.girdl.data.rdl.Token;
import com.antmicro.girdl.data.rdl.TokenType;
import com.antmicro.girdl.data.rdl.parser.TokenStream;
import com.antmicro.girdl.data.rdl.parser.ast.expression.ExpressionNode;
import com.antmicro.girdl.data.rdl.parser.ast.expression.StructLiteralNode;

import java.util.ArrayList;
import java.util.List;

public class ComponentInstanceNode extends SyntaxNode {

	public final String name;
	public final ComponentNode component;
	public final List<InstantiationNode> instantiations;
	public final InstantiationType type;
	public final StructLiteralNode parameters;

	public ComponentInstanceNode(Location location, ComponentNode component, String name, List<InstantiationNode> instantiations, InstantiationType type, StructLiteralNode parameters) {
		super(location);
		this.name = name;
		this.component = component;
		this.instantiations = instantiations;
		this.type = type;
		this.parameters = parameters;
	}

	public static ComponentInstanceNode parse(ComponentNode component, TokenStream stream, InstantiationType type, StructLiteralNode parameters) {

		Token identifier = stream.expect(TokenType.IDENTIFIER);
		String name = identifier.asString();
		List<InstantiationNode> instantiations = new ArrayList<>();

		// optional array or range specifier
		if (stream.match("[")) {
			TokenStream specifier = stream.block("[]", "array");
			ExpressionNode first = ExpressionNode.parseExpression(specifier);

			if (specifier.match(":")) {
				instantiations.add(new RangeInstantiationNode(identifier, first, ExpressionNode.parseExpression(specifier)));
			} else {
				instantiations.add(new InstantiationNode(identifier, InstantiationNode.Type.ARRAY, first));
			}

			specifier.assertEmpty();
		}

		if (stream.match("=")) {
			instantiations.add(new InstantiationNode(identifier, InstantiationNode.Type.ASSIGN, ExpressionNode.parseLiteral(stream)));
		}

		if (stream.match("@")) {
			instantiations.add(new InstantiationNode(identifier, InstantiationNode.Type.AT, ExpressionNode.parseLiteral(stream)));
		}

		if (stream.match("+=")) {
			instantiations.add(new InstantiationNode(identifier, InstantiationNode.Type.STRIDE, ExpressionNode.parseLiteral(stream)));
		}

		if (stream.match("%=")) {
			instantiations.add(new InstantiationNode(identifier, InstantiationNode.Type.ALIGN, ExpressionNode.parseLiteral(stream)));
		}

		return new ComponentInstanceNode(identifier, component, name, instantiations, type, parameters);
	}

}
