<?php /** @noinspection PhpUnused */

class container extends baseobject {
	
	protected static array $fields=array(
		'name'=>validator::REQUIRED,
		'containertypeid'=>array(validator::REQUIRED, validator::INTEGER),
	);
	
	protected static array $helpTexts=array(
		'name'=>'A unique identifier for the container',
		'containertypeid'=>'The type of container, e.g., Unipuck',
	);

	protected static string $adminSelect='SELECT SQL_CALC_FOUND_ROWS container.*,
				containercategory.id AS containercategoryid, 
				containercategory.name AS containercategoryname, 
				containertype.name AS containertypename,
				containertype.positions AS positions,
				project.name AS projectname
			FROM container, containertype, containercategory, project
			WHERE containertype.id=container.containertypeid 
			AND containercategory.id=containertype.containercategoryid 
			AND container.projectid=project.id';
	protected static string $normalSelect='SELECT SQL_CALC_FOUND_ROWS container.*,
				containercategory.id AS containercategoryid, 
				containercategory.name AS containercategoryname, 
				containertype.name AS containertypename,
				containertype.positions AS positions,
				project.name AS projectname 
			FROM container, containertype, containercategory, project
			WHERE containertype.id=container.containertypeid 
			AND containercategory.id=containertype.containercategoryid 
			AND container.projectid=project.id ';

	protected static bool $sharedProjectOverride=true;

    /**
     * @param array $request
     * @return array
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
	public static function create(array $request=[]): array {
		$project=project::getByName(baseproject::SHARED);
		if(!$project){
			throw new NotFoundException('Could not read shared project.');
		}
		$request['projectid']=$project['id'];
		if('dummypin'==$request['name']){
			$pinType=containertype::getByName('Pin');
			if(!$pinType){
				throw new BadRequestException('Cannot create a dummy pin. No container type called Pin.');
			}
			$request=array(
					'name'=>str_replace('.','_','dummypin_'.microtime(true)),
					'containertypeid'=>$pinType['id'],
					'projectid'=>$project['id']
			);
		} else {
		    $containerTypeId=$request['containertypeid'];
		    $containerType=containertype::getById($request['containertypeid']);
		    if(!$containerType){
		        throw new BadRequestException('No container type with ID '.$containerTypeId);
		    }
		    if(!static::canCreate()){
                throw new ForbiddenException('You cannot create containers. See your administrator.');
            }
		    if(!session::isAdmin()  && !session::isTechnician()){
				$containerCategory=containercategory::getById($containerType['containercategoryid']);
		        $usersCanCreateInCategory=1*$containerCategory['userscancreate'];
		        if(!$usersCanCreateInCategory){
		            throw new ForbiddenException('Only administrators and technicians can create a '.strtolower($containerCategory['name'].'. See your administrator.'));
		        }
		    }
		}
		session::becomeAdmin();  //Because the user needs to create in the Shared project, which they can't do
        $container=parent::createByClassName($request,'container');
		session::revertAdmin();
		return $container;
	}

    /**
     * @param int $id The container of the ID
     * @param array $request The request parameters
     * @return array
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
	public static function update(int $id, array $request=[]): array {
	    $container=static::getById($id);
	    if(isset($request['action']) && 'unpackAll'==$request['action']){
	        //get all containercontents where $id is parent
	        //recursive-delete each one
	        containercontent::deleteContainerContentsRecursively($id);
	        return array('updated'=>$container);
	    }
	    throw new BadRequestException('Nothing to do');
	}

    /**
     * @return bool
     * @throws BadRequestException
     * @throws NotFoundException
     * @throws ServerException
     */
	public static function canCreate(): bool {
	    /*
	     * Admins and technicians can create containers of any category
	     */
		if(session::isAdmin()){ return true; }
		$grp=usergroup::getByName(usergroup::TECHNICIANS);
		if(usergroup::userisingroup($grp['id'])){
		    return true;
		}
		/*
		 * Regular users can only create containers in permitted categories
		 */
		$creatableCategories=containercategory::getByProperty('userscancreate', 1);
		return !empty($creatableCategories);
	}

	/**
	 * @param int $id
	 * @param array $request
	 * @return array
	 * @throws BadRequestException
	 * @throws NotFoundException
	 * @throws ServerException
	 */
	public static function getfullcontents(int $id, array $request=[]): array {
		$request['recursive']='yes';
		$rows=static::getcontents($id,$request);
		return array(
			'total'=>count($rows),
			'rows'=>$rows
		);
	}

	/**
	 * @param int $id
	 * @param array $request
	 * @return array
	 * @throws BadRequestException
	 * @throws NotFoundException
	 * @throws ServerException
	 */
	public static function getcontents(int $id, array $request=[]): array {
		if(!isset($request['recursive'])){
            return containercontent::getByProperties(array(
                    'parent'=>$id,
                    'iscurrent'=>1
            ), $request);
		}
		$parent=container::getById($id);
		if(!$parent){ throw new NotFoundException('Parent is not a container'); }
		return container::getContentsRecursively($parent);
	}

	/**
	 * @param int $id
	 * @param array $request
	 * @return array
	 * @throws BadRequestException
	 * @throws NotFoundException
	 * @throws ServerException
	 */
    public static function getparentcontainer(int $id, array $request=[]): array {
        $containerContent=containercontent::getByProperties(array(
            'parent'=>$id,
            'iscurrent'=>1
        ), $request);
        if(!$containerContent){ return $containerContent; }
        if(1<$containerContent['total']){ throw new ServerException("Container with ID $id has more than one current parent. This should not happen."); }
        $containerContent=$containerContent['rows'][0];
        return container::getById($containerContent['parent']);
    }

	/**
	 * @param int $id
	 * @param array $request
	 * @return array
	 * @throws BadRequestException
	 * @throws NotFoundException
	 * @throws ServerException
	 */
	public static function gethistoricalcontents(int $id, array $request=[]): array {
		return containercontent::getByProperties(array(
				'parent'=>$id,
				'iscurrent'=>0
		), $request);
	}

    /**
     * @param $parent
     * @return array
     * @throws BadRequestException
     * @throws ServerException
     * @throws NotFoundException
     */
	public static function getContentsRecursively(array $parent): array {
	    if(isset($parent['positions'])){
            $numPositions=$parent['positions'];
            $positions=array_fill(0,(int)$numPositions+1,null);
	    } else {
	        $positions=array();
	    }
		$positions[0]="dummy";
		$contents=containercontent::getByProperties(array(
				'parent'=>$parent['id'],
				'iscurrent'=>1
		));
		if(isset($contents['rows'])){
			foreach ($contents['rows'] as $c){
				if("container"==$c['childtype']){
					$c['childobject']['record']['childitems']=container::getContentsRecursively($c['childobject']['record']);
				} else if("crystal"==$c['childtype']){
					$shipmentId=$c['shipmentid'];
					$diffractionRequests=false;
					if(isset($c['childobject']['record']['id'])){
					    $crystalId=$c['childobject']['record']['id'];
					    $diffractionRequests=diffractionrequest::getByProperties(array(
					        'crystalid'=>$crystalId,
					    ));
					} else {
					    $c['childobject']['record']['crystalhidden']=true;
					}
					$actionOnReturn='';
					$diffractionRequestId='';
					$remoteCrystalId='';
					$shippingComment='';
					$diffractionType='';
					$observedResolution='';
					$requiredResolution='';
					$minimumResolution='';
					$diffractionRequest=false;
					if(isset($diffractionRequests['rows'])){
					    if(1==count($diffractionRequests['rows'])){
					        $diffractionRequest=$diffractionRequests['rows'][0];
					    } else {
					        foreach($diffractionRequests['rows'] as $dr){
					            if($dr['shipmentid']==$shipmentId){
					                $diffractionRequest=$dr;
					                break;
					            } else if(!$diffractionRequest && ""==$shipmentId){
					                $diffractionRequest=$dr;
					                //but keep looking for one with the shipment ID explicitly set
					            }
					        }
					    }
					}
					$remoteCrystalUrl=null;
					if($diffractionRequest){
					    $actionOnReturn=$diffractionRequest['actiononreturn'];
					    $diffractionRequestId=$diffractionRequest['id'];
					    $remoteCrystalId=$diffractionRequest['crystalidatremotefacility'];
					    $remoteCrystalUrl=$diffractionRequest['crystalurlatremotefacility'];
					    $shippingComment=$diffractionRequest['comment'];
					    $diffractionType=$diffractionRequest['diffractiontype'];
					    $observedResolution=$diffractionRequest['observedresolution'];
					    $requiredResolution=$diffractionRequest['requiredresolution'];
					    $minimumResolution=$diffractionRequest['minimumresolution'];
					}
					
					$c['childobject']['record']['actiononreturn']=$actionOnReturn;
					$c['childobject']['record']['diffractionrequestid']=$diffractionRequestId;
					$c['childobject']['record']['crystalidatremotefacility']=$remoteCrystalId;
					$c['childobject']['record']['crystalurlatremotefacility']=$remoteCrystalUrl;
					$c['childobject']['record']['shippingcomment']=$shippingComment;
					$c['childobject']['record']['diffractiontype']=$diffractionType;
					$c['childobject']['record']['observedresolution']=$observedResolution;
					$c['childobject']['record']['requiredresolution']=$requiredResolution;
					$c['childobject']['record']['minimumresolution']=$minimumResolution;
					
				}
				$c['childobject']['record']['objecttype']=$c['childobject']['objecttype'];
				$positions[$c['position']]=$c['childobject']['record'];
				$positions[$c['position']]['containercontentid']=$c['containercontentid'];
			}
		}
		return $positions;
	}
	
}