<?php

class WPML_TM_XLIFF {
	private $body;
	private $dom;
	private $dtd;
	private $file;
	private $file_header;
	private $file_reference;
	private $phase_group;
	private $root;
	private $trans_units;
	private $xliff_version;

	const XLIFF_CUSTOM_ATTRIBUTES_NAMESPACE = 'https://cdn.wpml.org/xliff/custom-attributes.xsd';

	public function __construct( $xliff_version = '1.2', $xml_version = '1.0', $xml_encoding = 'utf-8' ) {
		$this->dom = new DOMDocument( $xml_version, $xml_encoding );

		$this->root        = $this->dom->createElement( 'xliff' );
		$this->file        = $this->dom->createElement( 'file' );
		$this->file_header = $this->dom->createElement( 'header' );
		$this->body        = $this->dom->createElement( 'body' );

		$this->xliff_version = $xliff_version;
	}

	public function setFileAttributes( $attributes ) {
		foreach ( $attributes as $name => $value ) {
			$this->file->setAttribute( $name, is_null( $value ) ? '' : $value );
		}

		return $this;
	}

	public function setPhaseGroup( array $args ) {
		if ( $args ) {
			$phase_items = array();
			foreach ( $args as $name => $data ) {
				if (
					$name
					&& array_key_exists( 'process-name', $data )
					&& array_key_exists( 'note', $data )
					&& $data['note']
				) {

					$phase = $this->dom->createElement( 'phase' );
					$phase->setAttribute( 'phase-name', $name );
					$phase->setAttribute( 'process-name', $data['process-name'] );
					$note            = $this->dom->createElement( 'note' );
					$note->nodeValue = $data['note'];
					$phase->appendChild( $note );
					$phase_items[] = $phase;

				}
			}

			if ( $phase_items ) {
				$this->phase_group = $this->dom->createElement( 'phase-group' );
				foreach ( $phase_items as $phase_item ) {
					$this->phase_group->appendChild( $phase_item );
				}
			}
		}

		return $this;
	}

	public function setReferences( array $references ) {
		if ( $references ) {
			foreach ( $references as $name => $value ) {
				if ( ! $value ) {
					continue;
				}

				if ( ! $this->file_reference ) {
					$this->file_reference = $this->dom->createElement( 'reference' );
				}

				$reference = $this->dom->createElement( $name );
				$reference->setAttribute( 'href', $value );
				$this->file_reference->appendChild( $reference );
			}
		}

		return $this;
	}


	public function setTranslationUnits( $trans_units ) {
		if ( $trans_units ) {
			foreach ( $trans_units as $trans_unit ) {
				$trans_unit_element = $this->dom->createElement( 'trans-unit' );
				if ( array_key_exists( 'attributes', $trans_unit ) && is_array( $trans_unit['attributes'] ) ) {
					foreach ( $trans_unit['attributes'] as $name => $value ) {
						$trans_unit_element->setAttribute( $name, $value );
					}
				}
				$this->appendData( 'source', $trans_unit, $trans_unit_element );
				$this->appendData( 'target', $trans_unit, $trans_unit_element );

				if ( ! empty( $trans_unit['note']['content'] ) ) {
					$note = $this->dom->createElement( 'note' );
					$note->nodeValue = 'wrap_tag:' . $trans_unit['note']['content'];
					$trans_unit_element->appendChild( $note );
				}

				if ( ! empty( $trans_unit['extradata'] ) && is_array( $trans_unit['extradata'] ) ) {
					$tool_extradata_element = $this->dom->createElement( 'tool:extradata' );
					foreach ( $trans_unit['extradata'] as $attr_name => $attr_value ) {
						$tool_extradata_element->setAttribute( $attr_name, $attr_value );
					}
					$trans_unit_element->appendChild( $tool_extradata_element );
				}

				$this->trans_units[] = $trans_unit_element;
			}
		}

		return $this;
	}

	private function appendData( $type, $trans_unit, $trans_unit_element ) {
		if ( array_key_exists( $type, $trans_unit ) ) {
			$source       = $this->dom->createElement( $type );
			$datatype     = isset( $trans_unit['attributes']['datatype'] ) ? $trans_unit['attributes']['datatype'] : '';
			$source_cdata = $this->dom->createCDATASection(
				$this->validate( $datatype, $trans_unit[ $type ]['content'] )
			);
			$source->appendChild( $source_cdata );

			if ( array_key_exists( 'attributes', $trans_unit[ $type ] ) ) {

				foreach ( $trans_unit[ $type ]['attributes'] as $name => $value ) {
					$source->setAttribute( $name, $value );
				}
			}

			$trans_unit_element->appendChild( $source );
		}
	}

	private function validate( $datatype, $content ) {
		if ( 'html' === $datatype ) {
			$validator = new WPML_TM_Validate_HTML();

			$validator->validate( $content );
			return $validator->get_html();
		}

		return $content;
	}

	public function toString() {
		$this->compose();

		$xml = $this->dom->saveXML();

		return $xml ? trim( $xml ) : '';
	}

	private function compose() {
		$this->dom->xmlStandalone = false;

		$this->setRoot( $this->xliff_version );

		if ( $this->dtd ) {
			$this->dom->appendChild( $this->dtd );
		}

		if ( $this->phase_group ) {
			$this->file_header->appendChild( $this->phase_group );
		}
		if ( $this->file_reference ) {
			$this->file_header->appendChild( $this->file_reference );
		}

		if ( $this->trans_units ) {
			foreach ( $this->trans_units as $trans_unit ) {
				$this->body->appendChild( $trans_unit );
			}
		}

		$this->file->appendChild( $this->file_header );
		$this->file->appendChild( $this->body );
		$this->root->appendChild( $this->file );
		$this->dom->appendChild( $this->root );
	}

	private function setRoot( $version ) {
		if ( $version === '1.0' ) {
			$implementation = new DOMImplementation();

			$this->dtd = $implementation->createDocumentType(
				'xliff',
				'-//XLIFF//DTD XLIFF//EN',
				'http://www.oasis-open.org/committees/xliff/documents/xliff.dtd'
			);
		}
		$this->root->setAttribute( 'version', $version );
		$this->root->setAttribute( 'xmlns', 'urn:oasis:names:tc:xliff:document:' . $version );
		$this->root->setAttribute( 'xmlns:tool', self::XLIFF_CUSTOM_ATTRIBUTES_NAMESPACE );
	}

}
