<?php

namespace Planaday\Html\NodeTags\Core\ForEachTag;

use DOMException;
use DOMNode;
use Planaday\Html\NodeTags\InnerContentControl;
use Planaday\Html\NodeTags\Tag;
use Planaday\Html\NodeTags\TagCore;
use Planaday\Html\NodeTags\TagNotFullyInitializedException;
use Planaday\Html\Nodes\ParserNode;
use Traversable;

class ForEachTag implements Tag {
	use TagCore;
	use InnerContentControl;

	public function getNewNode(): DOMNode&ParserNode {
		if ( !isset( $this->originalNode ) ){
			throw new TagNotFullyInitializedException("The OriginalNode is not set");
		}

		$outputFragment = $this->originalNode->getUsableDocumentFragment();

		if(
			!isset($this->attributes["in"], $this->attributes["as"]) ||
			!(is_array($this->attributes["in"]) || $this->attributes["in"] instanceof Traversable) ||
			!is_string($this->attributes["as"])
		){
			return $outputFragment;
		}

		$in = $this->attributes["in"];
		$as = $this->attributes["as"];
		$limit = $this->attributes["limit"] ?? -1;

		if ( isset($this->attributes["key"]) && is_string($this->attributes["key"]) ){
			$keyAs = $this->attributes["key"];
		}

		$innerContent = $this->getInnerContentFragment($this->originalNode);
		$nodeData = $innerContent->getExtendedNodeData();

		$this->logDebug("Running foreach loop on array with key as " . ($keyAs ?? "<undefined>") . " and value as " . $as .".");

		$implodeWith = $this->attributes["implode"] ?? null;
		$firstItem = true;

		foreach ($in as $key => $value){
			if ( $limit == 0 ) break;
			$limit--;

			if ( !$firstItem && $implodeWith !== null ){
				try {
					$element = $outputFragment->ownerDocument->createElement("pad-core-xml_fragment_tag");
					$element->setAttribute("xml", $implodeWith);
					$outputFragment->appendChild($element);
				} catch ( DOMException ){
					$this->logWarning("Implode element could not be created");
				}
			}

			$itemNode = $innerContent->cloneNode(true);
			$itemData = clone $nodeData;
			$itemData->data[$as] = $value;
			if ( isset($keyAs) ) $itemData->data[$keyAs] = $key;

			$itemNode->setExtendedNodeData( $itemData );

			$outputFragment->appendChild($itemNode);
			$firstItem = false;
		}

		return $outputFragment;
	}

	public function getTagDir(): string {
		return '';
	}
}