<?php class screenfromrockmaker extends screen {

    protected static array $fields=array(
        'name'=>validator::REQUIRED,
        'manufacturer'=>validator::REQUIRED,
        'catalognumber'=>validator::ANY,
        'path'=>validator::REQUIRED
    );

    private static string $baseUri='https://formulatrix.com/screens/';

    public static function getAll(array $request=[]): array {
        $screens=session::get('RockMakerScreens');
        if(!$screens){
            $screens=static::getRockMakerScreens();
            session::set('RockMakerScreens', $screens);
        }

        foreach ($screens as &$manufacturer){
            if(!isset($manufacturer['screens'])){
                continue;
            }
            foreach ($manufacturer['screens'] as &$screen){
                $existing=screen::getByProperties(array(
                    'manufacturer'=>$manufacturer['manufacturer'],
                    'name'=>$screen['name']
                ), $request);
                if(isset($existing['rows'])){
                    $screen['installed']=1;
                    $screen['id']=$existing['rows'][0]['id'];
                } else {
                    $screen['installed']=0;
                }
            }
        }

        return array(
            'total'=>count($screens),
            'rows'=>$screens
        );
    }

    public static function create(array $request=[]): array {

        //try to create, will fail if already exists

		$url=str_replace(' ','%20',$request['path']);
		if(!str_starts_with($url, static::$baseUri)){
			$url=static::$baseUri.$url;
		}
        $parts=array_reverse(explode('/', $request['path']));
        $tempDir=rtrim(config::get('core_imagestore'),'/').'/screens_temp/'.$parts[1].'/'.$parts[0];
        $fileName=$parts[0];
        $zipFile=$tempDir.'/'.$fileName;
        $cleanUp=[];

	    try {
            if(!file_exists($tempDir) && !@mkdir($tempDir, 0777, true)){
                throw new ServerException('Could not create temporary directory on server ['.$tempDir.']');
            }
            $cleanUp[]=$zipFile;
            $out=@fopen($zipFile,"wb");
            if(false===$out){
                throw new ServerException('Could not download update because destination path '.$zipFile.' is not writable.');
            }
            $ch=curl_init();
            curl_setopt($ch, CURLOPT_FILE, $out);
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false);
            // https://stackoverflow.com/questions/56865217/php-curl-error-http-2-stream-0-was-not-closed-cleanly-protocol-error-err-1
            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
            curl_exec($ch);
            $error=curl_error($ch);
            if($error){
                throw new ServerException('Error getting screen file from Formulatrix: '.$error);
            }
            curl_close($ch);
            @fclose($out);
            if(!@file_exists($zipFile)){
                throw new ServerException('Could not save downloaded screen to temporary location on server');
            }

            $zip=new ZipArchive();

            if(!@$zip->open($zipFile)){
                throw new ServerException('Could not open downloaded zip file');
            }
            $numFiles=$zip->numFiles;
            for($i=0;$i<$numFiles;$i++){
                $containedFile=$zip->getNameIndex($i);
              if(str_ends_with($containedFile, '.xml')){
                    $zip->extractTo($tempDir, $containedFile);
                    $cleanUp[]=rtrim($tempDir,'/').'/'.$containedFile;
                    $xmlFiles[]=rtrim($tempDir,'/').'/'.$containedFile;
                }
            }
            $zip->close();

            if(empty($xmlFiles)){
                throw new ServerException('Found no XML files in downloaded zip file. Cannot add screen.');
            } else if(1!==count($xmlFiles)){
                throw new ServerException('Found more than one XML file in downloaded zip file. Cannot add screen.');
            }

			return screen::create(array(
				'name'=>$request['name'],
				'manufacturer'=>$request['manufacturer'],
				'catalognumber'=>$request['catalognumber'],
				'isstandard'=>true,
				'tempfile'=>$xmlFiles[0],
				'mimetype'=>'text/xml'
			));

		} finally {
            $imageStore=rtrim(config::get('core_imagestore'),'/');
            foreach ($cleanUp as $path){
                @unlink($path);
                while(rtrim($path,'/')!=rtrim($imageStore,'/')){
                    @rmdir($path);
                    $parts=explode('/', $path, -1);
                    $path=implode('/',$parts);
                }

            }
        }

    }

    /**
     * @return array
     * @throws ServerException
	 * Public for test
     */
    public static function getRockMakerScreens(): array {
		if(!class_exists('DOMDocument')){
			throw new ServerException("Show this to your administrator: Cannot get list of screens from Formulatrix. [Class DOMDocument does not exist.]");
		} else if(!function_exists('curl_init')){
			throw new ServerException("Show this to your administrator: Cannot get list of screens from Formulatrix. [Function curl_init does not exist.]");
		}

        $url='https://formulatrix.com/protein-crystallization-systems/rock-maker-crystallization-software/';
        $ch = curl_init($url);
        $options = array(
            CURLOPT_COOKIEFILE => '',
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_RETURNTRANSFER  => true,
            CURLOPT_HEADER          => false,
            CURLOPT_CONNECTTIMEOUT  => 10,
            CURLOPT_TIMEOUT         => 20,
            CURLOPT_SSL_VERIFYHOST  => 0,
            CURLOPT_SSL_VERIFYPEER  => false,
            CURLOPT_UNRESTRICTED_AUTH => true
        );
        curl_setopt_array($ch,$options);
        $data = curl_exec($ch);
		$error=curl_error($ch);
		curl_close($ch);
        if(false===$data){
            throw new ServerException('Show this to your administrator: [Could not retrieve list of screens. ('.$error.')]');
        }

		$page=new DOMDocument();
		if(!@$page->loadHTML($data)){
			throw new ServerException('Show this to your administrator: [Could not parse Formulatrix page into DOMDocument]');
		}
		$resources=$page->getElementById('resources');
		$tables=$resources->getElementsByTagName('table');
		$manufacturers=[];
		foreach ($tables as $table) {
			$parentDiv=$table->parentNode;
			if(!$parentDiv){ continue; }
			$previousDiv=$parentDiv->previousElementSibling;
			if(!$previousDiv){ continue; }
			$links=$previousDiv->getElementsByTagName('a');
			if(!$links){ continue; }
			$manufacturerName=trim($links[0]->textContent);
			$manufacturerAndScreens=array(
				'manufacturer'=>$manufacturerName,
				'screens'=>[]
			);
			$rows=$table->getElementsByTagName("tr");
			foreach ($rows as $tr){
				$cells=$tr->getElementsByTagName("td");

				if(4==count($cells)){
					$cell0=trim($cells[0]->textContent);
					$cell1=($cells[1]->getElementsByTagName('a')?$cells[1]->getElementsByTagName('a')[0]->getAttribute('href'):'');
					$cell2=trim($cells[2]->textContent);
					$cell3=(empty($cells[3]->getElementsByTagName('a'))?'':$cells[3]->getElementsByTagName('a')[0]->getAttribute('href'));
					if(''!==$cell0 && ''!==$cell1){
						$manufacturerAndScreens['screens'][]=array(
							'manufacturer'=>$manufacturerName,
							'catalognumber'=>'',
							'name'=>$cell0,
							'path'=>$cell1
						);
					}
					if(''!==$cell2 && ''!==$cell3){
						$manufacturerAndScreens['screens'][]=array(
							'manufacturer'=>$manufacturerName,
							'catalognumber'=>'',
							'name'=>$cell2,
							'path'=>$cell3
						);
					}
				} else if(6==count($cells)){
					$cell0=trim($cells[0]->textContent);
					$cell1=trim($cells[1]->textContent);
					if(!empty($cell0) && empty($cell1)) {
						$cell2=$cells[2]->getElementsByTagName('a');
						if(count($cell2)){
							$cell2=$cell2[0]->getAttribute("href");
							$manufacturerAndScreens['screens'][]=array(
								'manufacturer' => $manufacturerName,
								'catalognumber' => $cell0,
								'name' => $cell1,
								'path' => $cell2
							);
						}
					}
					$cell3=trim($cells[3]->textContent);
					$cell4=trim($cells[4]->textContent);
					if(!empty($cell3) && !empty($cell4)){
						$cell5=$cells[5]->getElementsByTagName('a');
						if(count($cell5)){
							$cell5=$cell5[0]->getAttribute("href");
							$manufacturerAndScreens['screens'][]=array(
								'manufacturer'=>$manufacturerName,
								'catalognumber'=>$cell3,
								'name'=>$cell4,
								'path'=>$cell5
							);
						}
					}
				}
			}
			if(!empty($manufacturerAndScreens['screens'])){
				$manufacturers[]=$manufacturerAndScreens;
			}
		}
		usort($manufacturers, function ($item1, $item2) {
			return strtolower($item1['manufacturer']) <=> strtolower($item2['manufacturer']);
		});
		return $manufacturers;
    }

    public static function getById(int $id): ?array {
        throw new ServerException('not implemented');
    }

    public static function getByName(string $name): ?array {
        throw new ServerException('not implemented');
    }

    public static function update(int $id, $request=[]): array {
        throw new ServerException('not implemented');
    }

    public static function getByProperties(array $keyValuePairs, array $request=[]): ?array {
        throw new ServerException('not implemented');
    }

    public static function getByProperty(string $key, string $value, array $request=[]): ?array {
        throw new ServerException('not implemented');
    }

    public static function delete(int $id): array {
        throw new ServerException('not implemented');
    }

}
