<?
class html_element {
	private $margin = NULL;
	private $border = NULL;
	private $padding = NULL;
	private $layout = NULL;
	public $is_pseudo_element = false;
	public function __construct($window=NULL, $parent_element=NULL) {
		$this->computed_style = $object->create();
		$this->parent_element = $parent_element;
		if($window != NULL) {
			$this->window = $window;
		} else {
			if($this->parent_element != NULL) {
				$this->window = $this->parent_element->get_window();
			}
		}
		$this->attributes = $object->create();
		if($object->isset($this->__init)) {
			$this->__init();
		}
	}
	private $script = '';
	public function set_script($script) {
		$this->script = $script;
	}
	public function init_tag($tag_name) {
		$this->tag_name = $tag_name;
	}
	public function query_selector($selector) {
		return $this->window->get_document()->query_selector($selector, $this);
	}
	public function in_body() {
		if($this->tag_name == 'body') {
			return true;
		}
		if($this->parent_element != NULL) {
			return $this->parent_element->in_body();
		}
		return false;
	}
	private $media_tab;
	public function get_media_tab() {
		return $this->media_tab;
	}
	public function remake($call=true) {
		if($this->margin != NULL) {
			$this->margin->clear();
			$this->margin = NULL;
		}
		if($this->padding != NULL) {
			$this->padding->clear();
			$this->padding = NULL;
		}
		if($this->layout != NULL) {
			$this->layout->clear();
			$this->layout = NULL;
		}
		foreach($this->children as $child) {
			$child->remake(false);
		}
		/*if($call) {
			$this->make_layout();
		}*/
	}

	public function remake_children() {

		foreach($this->children as $child) {
			$child->remake(false);
		}
	}

	public function replace_with($elements) {
		$children = $this->parent_element->get_children();
		$children = [...$children];
		$self_index = $object->index_of($children, $this);

		if($self_index != (-1)) {
			$object->remove_item($children, $this);
			foreach($elements as $element) {
				$object->insert($children, $element, $self_index);
				$self_index = $self_index + 1;
			}
			$this->layout->off('pseudo_stack_linebreak');
			$this->parent_element->set_children($children);
			$this->parent_element->remake(true);
		}
	}

	public function remove_from_parent() {
		$index = $this->parent_element->get_child_index($this);
		$children = $this->parent_element->get_children();
		if($index != (-1)) {
			$object->splice($children, $index, 1);
			$this->remake(false);
		}
	}

	private $stack_layouts = NULL;

	public $last_box_values = NULL;

	public $inline_children = [];

	private $pseudo_calculation = false;

	public function get_child_index($child) {
		return $object->index_of($this->children, $child);
	}

	public $previous_children = NULL;

	public function make_layout($from_window=false/*, $return_partition=false, $generate_pseudo_stacks=true*/) {

		if($this->in_body()) {
			$object->log('in body');
			if($this->layout === NULL) {
				$object->log('layout null');
				if($this->parent_element != NULL && !$from_window) {
					$object->log('has parent element');
					$layout_box = $this->get_box();
					$object->log($object->toJSON($this->get_box_values()));
					$object->log($object->toJSON($layout_box));

					$this->last_box_values = $layout_box['outest'];
					

					
					$parent = $this->parent_element->get_layout();
					$outest = NULL;
					if($object->isset($layout_box['margin_box'])) {
						$parent = $parent->make($this, $layout_box['margin_box']);	
						$this->margin = $parent;
					}
					$border_set = false;
					$border_to_set = NULL;
					if($object->isset($layout_box['main_box']['border'])) {
						$border_to_set = $layout_box['main_box']['border'];
					}
					if($object->isset($layout_box['padding_box'])) {
						$parent = $parent->make($this, $layout_box['padding_box']);	
						$this->padding = $parent;
						if($border_to_set != NULL) {
							$parent->set_border();
							$border_to_set = NULL;
						}
					}
					if($this->tag_name != 'video') {
						$this->layout = $parent->make($this, $layout_box['main_box']);	
						/*if($border_to_set != NULL) {
							$this->layout->set_border();
						}*/
					} else {
						$this->layout = $this->parent_element->get_layout()->make($this, $this->get_box(), true);
						$this->media_tab = $media->add_tab($this->layout);
					}

				} else if($this->window != NULL) {
					$layout_window = $this->window->get_layout();
					$this->layout = $layout_window->make($this, [
						'set_rectangle' => [
							0, 0, 0, 0
						]
					]);
				}
				$object->log('this tag name: '.$this->tag_name);
				if($this->tag_name == 'web') {
					$object->log('init web');
					$this->webview = $this->layout->assign_web_view($this->script);
					if($object->isset($this->attributes['type']) && $this->attributes['type'] == 'overlay') {
						if($object->isset($this->attributes['src'])) {
							$this->webview->load_file($this->attributes['src']);
						}
					} else {
						$set_webview = $this->webview;
					}
				} else if($this->tag_name == 'style') {
					if($this->children->length > 0) {
						$inner_text = $this->children[0];
					}
				}

				/*if(!$object->isset($this->layout_calculator)) {
					$this->layout_calculator = new layout($this);
				}*/

				$set_children_values = $this->get_children();
				$object->log('children: '.$set_children_values->length);
				foreach($set_children_values as $child) {
					if($object->instance_of($child, 'html_element')) {
						$object->log('make child');
						$intermediate_result = $child->make_layout(false, $return_partition); /*, $generate_pseudo_stacks*/
						$object->log($object->toJSON($this->outer_bounds()));
						if($return_partition && $intermediate_result != (-2)) {
							return $intermediate_result;
						}
					}
				}
			
			}
		}
		return (-2);
	}
	public function get_height($inner=false) {
		$set_width = 0;
		$box = $this->get_box();
		$set_width = $box['main_box']['set_height'];
		if($inner && $object->isset($box['padding_box'])) {
			$set_width = $box['padding_box']['set_height'];
		}
		if(!$inner) {
			if($object->isset($box['margin_box'])) {
				$set_width = $box['margin_box']['set_height'];
			}
		}
		if($set_width == NULL || $set_width == (-1)) {
			$set_width = $this->get_layout()->get_height();

			if(!$inner) {
				$box_values = $this->get_box_values();
				if($object->isset($box_values['padding'])) {
					$set_width = $set_width + (2*$box_values['padding']['value']);
				}
				if($object->isset($box_values['border'])) {
					$set_width = $set_width + (2*$box_values['border']['value']);
				}
				if($object->isset($box_values['margin'])) {
					$set_width = $set_width + (2*$box_values['margin']['value']);
				}
			}
		}
		return $set_width;
	}
	public function get_width($inner=false) {
		$set_width = 0;
		$box = $this->get_box();
				
		$box_values = $this->get_box_values();
		$width_type = $box_values['width_type'];
		if($width_type == 0) {
			$set_width = $box['main_box']['set_width'];
			if($inner && $object->isset($box['padding_box'])) {
				$set_width = $box['padding_box']['set_width'];
			}
			if(!$inner) {
				if($object->isset($box['margin_box'])) {
					$set_width = $box['margin_box']['set_width'];
				}
			}
		}
		if($set_width == NULL || $set_width == (-1) || $width_type == 1) {
			$set_width = $this->get_layout()->get_width();

			$object->log('layout width: '.$set_width);

			if(!$inner) {
				if($object->isset($box_values['padding'])) {
					$set_width = $set_width + (2*$box_values['padding']['value']);
				}
				if($object->isset($box_values['border'])) {
					$set_width = $set_width + (2*$box_values['border']['value']);
				}
				if($object->isset($box_values['margin'])) {
					$set_width = $set_width + (2*$box_values['margin']['value']);
				}
			}
		}
		return $set_width;
	}
	private $original_children = NULL;
	public function after($element) {
		$parent_children = $this->get_parent()->get_children();
		$parent_children = [...$parent_children];
		$index = $object->index_of($parent_children, $this);
		if($index != (-1)) {
			$after_elements = $object->splice($parent_children, $index, $parent_children->length - $index);
			$parent_children[] = $element;
			$parent_children = $object->concat($parent_children, $after_elements);
			$this->get_parent()->set_children($parent_children);
		}
	}
	public function outer_bounds() {
		$res = NULL;
		if($this->layout != NULL) {
			$res = $this->layout->get_result();
		}
		if($this->padding != NULL) {
			$res = $this->padding->get_result();
		}
		if($this->margin != NULL) {
			$res = $this->margin->get_result();
		}
		if($res != NULL) {
			$res['position']['x'] = $object->remove_negative($res['position']['x']);
			$res['position']['y'] = $object->remove_negative($res['position']['y']);
			$res['size']['width'] = $object->remove_negative($res['size']['width']);
			$res['size']['height'] = $object->remove_negative($res['size']['height']);
		}
		return $res;
	}	
	public function get_partition($child) {
		$index = $object->index_of($this->children, $child);
		$results = $object->splice($this->children, $index, $this->children->length - $index);
		return $results;
	}
	public function get_layout() {
		if($object->isset($this->layout) && $this->layout != NULL) {
			return $this->layout;
		}
		if($this->get_parent() != NULL) {
			$this->layout = $this->get_parent()->get_layout()->make($this, $this->get_box_values());
			return $this->layout;	
		}
		return NULL;
	}
	protected $inner_text;
	public function set_inner_text($inner_text) {
		$this->inner_text = $inner_text;
	} 
	public function get_inner_text() {
		return $this->inner_text;
	}
	protected $view;
	public function set_window($window) {
		$this->window = $window;
	}
	public function get_window() {
		return $this->window;
	}
	protected $window;
	protected $namespace;
	protected $parent_element;
	protected $tag_name = 'unknown';
	protected $classes = [];
	protected $id;
	public function get_parent() {
		return $this->parent_element;
	}
	public function init_pseudo($emulate) {
		$this->is_pseudo_element = true;
		$this->tag_name = 'div';
		$this->set_computed_style([
			'orientation' => 1,
			'width' => ['value' => 100, 'type' => '%']/*,*/
			/*'width' => ['value' => 300, 'type' => 'px'],*/
			/*'width' => $emulate->get_layout()->get_box()['width'],*/
			/*'width' => ['value' => $emulate->outer_bounds()['size']['width'], 'type' => 'px'],*/
			/*'height' => ['value' => 100, 'type' => 'px']*/
		]);
	}
	public function is_pseudo() {
		return $this->is_pseudo_element;
	}
	protected $computed_style = NULL;
	public function set_style($style) {
		if(!$object->isset($this->computed_style)) {
			$this->cmoputed_style = $object->create();
		}
		foreach($style as $key => $value) {
			$object->log('style: '.$key);
			$object->log($object->toJSON([$value]));
			$this->computed_style[$key] = $value;
		}
	}	
	public function set_style_by_name($property_name, $value) {
		$object->log($object->toJSON(['set_style_by_name', $property_name, $value]));
		$this->computed_style[$property_name] = $value;
		$object->log($object->toJSON(['set_style_by_name', $this->computed_style]));
	}
	public function reset_computed_style() {
		$this->computed_style = [];
	}
	public function get_computed_style() {
		return $this->computed_style;
	}
	public function attribute_is($attribute_name, $attribute_value) {
		if($object->isset($this->attributes[$attribute_name])) {
			if($object->strings->trim($this->attributes[$attribute_name]) == $object->strings->trim($attribute_value)) {
				return true;
			}
		}
		return false;
	}
	public function set_computed_style($style, $reset=false) {
		$this->computed_style = $style;
	}
	private $layout_calculator;
	public function get_layout_calculator() {
		if(!$object->isset($this->layout_calculator)) {
			$this->layout_calculator = new layout($this);
		}
		return $this->layout_calculator;
	}
	public function get_box() {
		if(!$object->isset($this->layout_calculator)) {
			$this->layout_calculator = new layout($this);
		}
		return $this->layout_calculator->get_box();
	}
	public function get_box_values() {
		$results = $object->create();
		$results['is_block'] = true;
		$results['is_inline'] = false;
		if($object->isset($this->attributes['class'])) {
			$results['classes_values'] = $object->toJSON($this->attributes['class']);
		}
		if($object->isset($this->computed_style['display'])) {
			if($this->computed_style['display'] == 'inline-block') {
				$results['is_inline'] = true;
			}
		}
		if($object->isset($this->computed_style['min-width'])) {
			$results['min-width'] = $this->computed_style['min-width']['value'];
			$results['min-width_type'] = 0;
			if($this->computed_style['min-width']['type'] == '%') {
				$results['min-width_type'] = 1;
			}
		}
		if($object->isset($this->computed_style['min-height'])) {
			$results['min-height'] = $this->computed_style['min-height']['value'];
			$results['min-height_type'] = 0;
			if($this->computed_style['min-height']['type'] == '%') {
				$results['min-height_type'] = 1;
			}
		}
		if($object->isset($this->computed_style['max-width'])) {
			$results['max-width'] = $this->computed_style['max-width']['value'];
			$results['max-width_type'] = 0;
			if($this->computed_style['max-width']['type'] == '%') {
				$results['max-width_type'] = 1;
			}
		}
		if($object->isset($this->computed_style['max-height'])) {
			$results['max-height'] = $this->computed_style['max-height']['value'];
			$results['max-height_type'] = 0;
			if($this->computed_style['max-height']['type'] == '%') {
				$results['max-height_type'] = 1;
			}
		}
		if($object->isset($this->computed_style['width'])) {
			$results['set_width'] = $this->computed_style['width']['value'];
			$results['width_type'] = 0;
			if($this->computed_style['width']['type'] == '%') {
				$results['width_type'] = 1;
			}
		}
		if($object->isset($this->computed_style['height'])) {
			if($this->computed_style['height'] === 'auto') {
				$results['auto_height'] = true;
			} else {
				$results['height_type'] = 0;
				$results['set_height'] = $this->computed_style['height']['value'];
				if($this->computed_style['height']['type'] == '%') {
					$results['height_type'] = 1;
				}
			}
		}
		if($object->isset($this->computed_style['padding'])) {
			$results['padding'] = $this->computed_style['padding'];
		}
		if($object->isset($this->computed_style['margin'])) {
			$results['margin'] = $this->computed_style['margin'];
		}
		if($object->isset($this->computed_style['border'])) {
			$results['border'] = $this->computed_style['border'];
		}
		if($object->isset($this->computed_style['orientation'])) {
			$results['orientation'] = $this->computed_style['orientation'];
		}
		if($object->isset($this->computed_style['overflow'])) {
			$results['overflow'] = $this->computed_style['overflow'];
		}
		if($object->isset($this->computed_style['display_alt'])) {
			$results['display'] = $this->computed_style['display_alt'];
		}
		if($object->isset($this->computed_style['horizontal_alignment'])) { 
			$results['horizontal_alignment'] = $object->to_number($this->computed_style['horizontal_alignment']);
		}
		if($object->isset($this->computed_style['vertical_alignment'])) { 
			$results['vertical_alignment'] = $object->to_number($this->computed_style['vertical_alignment']);
		}
		$rectangle = [-1, -1, -1, -1];
		$rectangle_type = [0, 0, 0, 0];
		if($object->isset($this->computed_style['left'])) {
			$rectangle[0] = $this->computed_style['left']['value'];
			if($this->computed_style['left']['type'] == '%') {
				$rectangle_type[0] = 1; 
			}
		}
		if($object->isset($this->computed_style['top'])) {
			$rectangle[1] = $this->computed_style['top']['value'];
			if($this->computed_style['top']['type'] == '%') {
				$rectangle_type[1] = 1; 
			}
		}
		if($object->isset($this->computed_style['right'])) {
			$rectangle[2] = $this->computed_style['right']['value'];
			if($this->computed_style['right']['type'] == '%') {
				$rectangle_type[2] = 1; 
			}
		}
		if($object->isset($this->computed_style['bottom'])) {
			$rectangle[3] = $this->computed_style['bottom']['value'];
			if($this->computed_style['bottom']['type'] == '%') {
				$rectangle_type[3] = 1; 
			}
		}
		$results['set_rectangle'] = $rectangle;
		$results['rectangle_type'] = $rectangle_type;
		$rectangle_addition = [0, 0, 0, 0];
		$rectangle_subtraction = [0, 0, 0, 0];
		if($object->isset($this->computed_style['left_addition'])) {
			$rectangle_addition[0] = $this->computed_style['left_addition']['value'];
		}
		if($object->isset($this->computed_style['top_addition'])) {
			$rectangle_addition[1] = $this->computed_style['top_addition']['value'];
		}
		if($object->isset($this->computed_style['width_addition'])) {
			$rectangle_addition[2] = $this->computed_style['width_addition']['value'];
		}
		if($object->isset($this->computed_style['height_addition'])) {
			$rectangle_addition[3] = $this->computed_style['height_addition']['value'];
		}
		if($object->isset($this->computed_style['left_subtraction'])) {
			$rectangle_subtraction[0] = $this->computed_style['left_subtraction']['value'];
		}
		if($object->isset($this->computed_style['top_subtraction'])) {
			$rectangle_subtraction[1] = $this->computed_style['top_subtraction']['value'];
		}
		if($object->isset($this->computed_style['width_subtraction'])) {
			$rectangle_subtraction[2] = $this->computed_style['width_subtraction']['value'];
		}
		if($object->isset($this->computed_style['height_subtraction'])) {
			$rectangle_subtraction[3] = $this->computed_style['height_subtraction']['value'];
		}
		$results['rectangle_addition'] = $rectangle_addition;
		$results['rectangle_subtraction'] = $rectangle_subtraction;
		return $results;
	}
	public function get_classes() {
		if($object->isset($this->attributes['class'])) {
			return $this->attributes['class'];
		}
		return [];
	}
	public function has_class($class_value) {
		if($object->isset($this->attributes['class'])) {
			foreach($this->attributes['class'] as $compare) {
				if($class_value == $compare) {
					return true;
				}
			}
		}	
		return false;
	}
	public function get_id() {
		if($object->isset($this->attributes['id'])) {
			return $this->attributes['id'];
		}
		return NULL;
	}
	protected $children = [];
	public function set_namespace($namespace) {
		$this->namespace = $namespace;
	}
	public function set_children($children, $set_original=false) {
		$this->children = $children;
		if($set_original) {
			$this->original_children = $children;
		}
	}
	public function set_parent($parent) {
		$this->parent_element = $parent;
	}
	public function add_child($child) {
		$child->set_parent($this);
		$this->children[] = $child;
	}
	public function get_original_children() {
		return $this->original_children;
	}
	public function set_original_children($children) {
		return $this->original_children = $children;
	}
	public function get_children() {
		return $this->children;
	}
	public function set_tag_name($tag_name) {
		$this->tag_name = $tag_name;
	}
	public function get_tag_name() {
		return $this->tag_name;
	}
	public function get_namespace() {
		return $this->namespace;
	}
	public function parse_tag($tag_value) {
		$values = $tag_value['value_set'];
		$attribute_values = $tag_value['attributes'];
		$value = $values[0];
		$preg_split_instance = new preg_split('\s+', $object->strings->trim($value), true);
		$split = $preg_split_instance->get();
		if($object->count($split) > 0) {
			$tag_name = $split[0];
			$this->set_tag_name($tag_name);
			if($object->isset($split[1])) {
				$values[0] = $split[1];
			} else {
				$values = [];
			}
		}
		$index_offset = 0;
		foreach($values as $key => $value) {
			if($object->strings->strpos($value, '=') !== (-1)) {
				$split = $object->strings->explode('=', $value);
				$attribute_name = $object->strings->trim($split[0]);
				$key_value = $key+$index_offset;
				$property_value = $object->strings->implode('', $attribute_values[$key_value]);
				$this->set_attribute($attribute_name, $property_value);
			} else {
				$this->set_attribute($object->strings->trim($value), NULL);
				$index_offset = $index_offset-1;
			}
		}
		return $this->tag_name;
	}
	protected $webview;
	public function get_webview() {
		return $this->webview;
	}
	protected $attributes = NULL;
	protected $style_manager;
	public function set_attribute($attribute_name, $value) {
		if($attribute_name == 'class') {
			$preg_split_instance = new preg_split('\s+', $value);
			$value = $preg_split_instance->get();
			$this->attributes[$attribute_name] = $value;
		} else if($attribute_name == 'style') {
			$this->attributes[$attribute_name] = $value;
			if($this->style_manager == NULL) {
				$this->style_manager = new style_manager();
			}
			$style_manager = $this->style_manager; 
			$style_manager->run($value);
			$styles = $style_manager->style_rules;
			$this->set_computed_style($styles);
		} else {
			$this->attributes[$attribute_name] = $value;
		}		
	}
}
?>

