<?php
ini_set('post_max_size', '100M');
//use Dompdf\Exception;

/**
 * Seguro_CroquiController
 *
 * @author Renato - 13/08/2010
 */
class Seguro_CroquiController extends Agro_Controller_Action {

	public function init() {
		$this->getHelper('layout')->disableLayout();
	}

	/**
	 * Lista Croquis da proposta
	 *
	 * @author Renato - 13/08/2010 - Sexta-Feira
	 */
	public function listarAction() {
		if ($this->getRequest()->getParam('id_proposta')) {
			$PropostaArquivos = new Seguro_Model_PropostasArquivos();
			$this->view->croquis = $PropostaArquivos->fetchAll("id_proposta = ".$this->getRequest()->getParam('id_proposta'));
			$this->view->show_view = $this->getRequest()->getParam('view');
			$this->view->hide_delete = $this->getRequest()->getParam('hidedelete');
		}
	}

	/**
	 * Lista Croquis da proposta
	 *
	 * @author Renato - 13/07/2011 - Quarta-Feira
	 */
	public function listAction() {
		$this->getHelper('ViewRenderer')->setNoRender();

		if (is_numeric($this->getRequest()->getParam('id'))) {
			$Propostas = new Seguro_Model_Propostas();
			$Proposta = $Propostas->find($this->getRequest()->getParam('id'))->current();
			$this->getResponse()->setBody($this->view->croquis($Proposta, array('list' => true)));
		}
	}

	/**
	 * Deleta um croqui do sistema
	 *
	 * @author Renato - 13/08/2010 - Sexta-Feira
	 */
	public function deletarAction() { 
		$this->getHelper('ViewRenderer')->setNoRender();
        $deleted = null;

		if ($this->getRequest()->getParam('name')) {
			$PropostaArquivos = new Seguro_Model_PropostasArquivos();
			$Propostas        = new Seguro_Model_Propostas();
			$Proposta         = $Propostas->find($this->getRequest()->getParam('id_proposta'))->current();
			$Produto          = $Proposta->produto();
			$deleted          = $PropostaArquivos->deleteCroquisName($this->getRequest()->getParam('name'), $this->getRequest()->getParam('id_proposta'));

			if ($deleted['status']) {

				if($Produto["ds_nome_cultura"] != "Pastagem"){
				    $PropostasCroquis = new Seguro_Model_PropostasCroquis();
				    $PropostasCroquis->deleteName($this->getRequest()->getParam('id_proposta'),$this->getRequest()->getParam('name'));
				}
				
				//só exclui fisicamente o croqui se ele não for arquivo pertencente a proposta em questão
				//não se for uma referência a imagem da proposta mãe.
				list($name, $proposta, $number) = explode('_',$this->getRequest()->getParam('name'));
				if ($proposta == $this->getRequest()->getParam('id_proposta')) {
					$sanitizedPath = realpath(PATH_CROQUI . "/" .$this->getRequest()->getParam('name'));

					if (file_exists($sanitizedPath)) {
						unlink($sanitizedPath);
					}
				}

                if (!empty($this->_requestParams['origemSolicitacaoEndosso'])) {
                    $deleted['origemSolicitacaoEndosso'] = true;
                }

				if (!$Proposta->isEndosso()) {
					(new Seguro_Model_PropostasHashOrcamento())->save($this->getRequest()->getParam('id_proposta'));
				}
			}
		}

		$this->getResponse()->setBody(Zend_Json::encode($deleted));
	}

	/**
	 * Faz o upload do croqui
	 *
	 * @author Renato - 13/08/2010
 	 */
	public function salvarAction()
    {
        $this->getHelper('ViewRenderer')->setNoRender();

        if ($this->getRequest()->getParam('id_proposta')) {
            $idProposta = !Agro_Util::filterVariable($this->getRequest()->getParam('id_proposta'))
                ? 0
                : (int)$this->getRequest()->getParam('id_proposta');

            $propostaArquivos = new Seguro_Model_PropostasArquivos();
            $count = $propostaArquivos->contaCroqui($idProposta);

            if ($count < QTD_CROQUIS_PROPOSTA) {
                if (!empty($_FILES) && is_array($_FILES)) {
                    foreach ($_FILES as $file) {
                        $tempFile = $file['tmp_name'];
                        $newName = "CROQUI_{$idProposta}_" . (date('Whis'));
                        $newName .= "." . Agro_Util::getExtension($file['name']);
                        $targetFile = PATH_CROQUI . "/" . $newName;

                        if (copy($tempFile, $targetFile)) {
                            if ($propostaArquivos->save($newName, $idProposta)) {
                                die('Croqui salvo com sucesso.');
                            } else {
                                die('Não foi possível salvar o croqui.');
                            }
                        } else {
                            die('Não foi possível salvar o croqui.');
                        }
                    }
                }
            } else {
                die('São permitidos ' . QTD_CROQUIS_PROPOSTA . ' por proposta.');
            }
        }
    }

	/**
	 * Formulario de Cadastro de Croqui
	 *
	 * @author Renato - 01/09/2010
	 */
	public function formAction() {
		$this->getHelper('layout')->disableLayout();

		$PropostaArquivos = new Seguro_Model_PropostasArquivos();

		$id_proposta = $this->getRequest()->getParam('id_proposta');
		$this->view->email = $this->getRequest()->getParam('email');
		$this->view->id_proposta = $id_proposta;

		$this->view->croquis = $PropostaArquivos->getPropostaCroquis($id_proposta);
	}

	/**
	 * Upload de Croqui
	 *
	 *
	 * @author Renato - 23/09/2010
	 * @obs $result ->  0 = Erro no Upload;
	 *	    			1 = Arquivo Salvo;
 	 *					2 = Quantidade exedida;
 	 * 					3 = Tipo de arquivo invalido;
 	*/
	public function uploadAction()
    {
		$this->getHelper('ViewRenderer')->setNoRender();
		$this->getHelper('layout')->disableLayout();
		$i = 0;

		if ($this->getRequest()->getParam('id_proposta')) {
            $idProposta = !Agro_Util::filterVariable($this->getRequest()->getParam('id_proposta'))
                ? 0
                : (int)$this->getRequest()->getParam('id_proposta');

			$propostaArquivos = new Seguro_Model_PropostasArquivos();
			$count = $propostaArquivos->contaCroqui($idProposta);
			$proposta = (new Seguro_Model_Propostas())->find($idProposta)->current();

			if ($count < QTD_CROQUIS_PROPOSTA) {
				if (!empty($_FILES) && is_array($_FILES)) {
				
					foreach ($_FILES as $file) {
						$extensao = pathinfo($file['name'],PATHINFO_EXTENSION);

						$newFile['name'] = $file['name'];
                        $newFile['tmp_name'] = $file['tmp_name'];

						if (is_array($file['name'])) {
							$newFile['name'] = $file['name'][$i];
							$newFile['tmp_name'] = $file['tmp_name'][$i];
						}

					    if (!in_array($extensao,["png", "jpg", "jpeg"])) {
					        $result = 3;
					    } else {
    						$tempFile = $newFile['tmp_name'];
    						$newName = "CROQUI_{$idProposta}_" . (date('Whis'));
    						$newName .= ".".Agro_Util::getExtension($newFile['name']);
    						$targetFile =  PATH_CROQUI . "/" . $newName;

    						if (copy($tempFile, $targetFile)) {
    							if ($propostaArquivos->save($newName, $idProposta, true)) {
    						        $result = 1;
    							} else {
    								$result = 0;
    							}
    						} else {
    							$result = 0;
    						}
					    }
					    
					    $i++;
					}

					if ($result == 1 && !$proposta->isEndosso()) {
						$hash = (new Seguro_Model_PropostasHashOrcamento())->save($idProposta);
						if (!$hash) {
							throw new Exception("Não foi possível criar a hash do orçamento.");
						}
					}
				}
			} else {
				$result = 2;
				echo '<script>alert("Atenção! Não foi possível salvar o croqui.\nNúmero máximo de 2 croquis atingido.");</script>';
			}
		}
		
        $script = "<script>window.top.window.stopUpload($result);";
		$script .= "window.top.window.$.listCroqui({$proposta->id}, '', {$this->getRequest()->getParam('hide_delete')});";

        if (
            $result === 1
            && $this->getRequest()->has('origemSolicitacaoEndosso')
            && $this->getRequest()->getParam('origemSolicitacaoEndosso') === 'true'
        ) {
            $script .= "window.top.window.$.croquiSalvo();";
        }

        $script .= "</script>";

		$this->getResponse()->setBody($script);
	}

	public function drawAction() {
		$this->getHelper('layout')->disableLayout();
		$modelProposta = new Seguro_Model_Propostas();
		$this->view->form = new Seguro_Form_Croqui();

		$Proposta = $modelProposta->find($this->getRequest()->getParam('id_proposta'))->current();
		$this->view->coordenadas = Agro_Util::coordenadas($Proposta->propriedade()['ds_coordenadas']);
		$this->view->id_proposta = $this->getRequest()->getParam('id_proposta');
		$this->view->id_solicitacao = $this->getRequest()->getParam('id_solicitacao');
		$this->view->id_laudo = $this->getRequest()->getParam('id_laudo');

		$produto = $Proposta->produto();
		if($produto["ds_nome_cultura"] == "Pastagem"){
			$this->view->isPastagem = true;
		}

		//recupera croqui caso já exista
		$PropostasCroquis = new Seguro_Model_PropostasCroquis();

		if (($this->getRequest()->getParam('last') == 0) && (!$this->getRequest()->getParam('id_solicitacao')) && !$this->getRequest()->getParam('id_laudo')) {
			$Croquis = $PropostasCroquis->getCroquis($this->getRequest()->getParam('id_proposta'));
		} elseif ($this->getRequest()->getParam('id_solicitacao')) {
			$Croquis = $PropostasCroquis->getCroquisSolicitacao($this->getRequest()->getParam('id_solicitacao'));
			if (count($Croquis) <= 0) {
				$Croquis = $PropostasCroquis->getCroquis($this->getRequest()->getParam('id_proposta'));	
			}
		} elseif ($this->getRequest()->getParam('id_laudo')) {
			$RegulacaoCroquis = new Regulacao_Model_Croquis();
			$Croquis = $RegulacaoCroquis->getCroquis($this->getRequest()->getParam('id_laudo'));
			if (count($Croquis) <= 0) { //se não encontrar nenhum croqui já desenhado pelo perito pega o croqui da proposta
				$Croquis = $PropostasCroquis->getCroquis($this->getRequest()->getParam('id_proposta'));
			}
		} else {
			$Croquis = $PropostasCroquis->getLastInsertCroqui($this->getRequest()->getParam('id_proposta'));
		}
				
		$itens = $this->assembleSede($Proposta, $pins_coords, $sede, $showSede);
		foreach ($itens as $item1) {
    		foreach ($Croquis as &$item2) {
        		if ($item1['is_descricao_item'] === $item2['ds_nome']) {
         			$item2['id_item'] = $item1['id_item'];
        		}
    		}
		}
		unset($item2);
		$this->view->js_pols = $this->assembleQuadras($Croquis, $this->view->isPastagem);
        $this->view->coordenadas_itens = null;

        if (!empty($Croquis)) {
            preg_match('/({.*?})/', preg_replace('/[\[\]]/', '', $Croquis[0]['ds_coordenadas']), $coordenadasItem);

            if (!empty($coordenadasItem[0])) {
                $coordenadasItem = preg_replace('/[{}]/', '', $coordenadasItem[0]);
                $coordenadasItem = str_replace('"latitude":', '', $coordenadasItem);
                $coordenadasItem = str_replace('"longitude":', '', $coordenadasItem);
                $coordenadasItem = explode(',', $coordenadasItem);

                $this->view->coordenadas_itens['latitude'] = $coordenadasItem[0];
                $this->view->coordenadas_itens['longitude'] = $coordenadasItem[1];
            }
        }

		$this->view->itens = $itens;
		$this->view->pins_coords = $pins_coords;
		$this->view->hidedelete = 'false';
		$this->view->origemSolicitacaoEndosso = 'false';

		if ($this->getRequest()->has('hidedelete') && $this->getRequest()->getParam('hidedelete') === 'true') {
            $this->view->hidedelete = 'true';
        }

        if ($this->getRequest()->has('origemSolicitacaoEndosso') && $this->getRequest()->getParam('origemSolicitacaoEndosso') === 'true') {
            $this->view->origemSolicitacaoEndosso = 'true';
        }

		if ($showSede) $this->view->sede = $sede;
	}

	function assembleSede(object $Proposta, &$pinsCoords='', &$sede='', &$showSede=''): array {
		$PropostasPropriedades = new Seguro_Model_PropostasPropriedades();
		$coord_talhao_sede = $PropostasPropriedades->hasSedeNoTalhao($Proposta->id);

		if ($coord_talhao_sede) {
			$coords = Agro_Util::coordenadas($coord_talhao_sede);
			$sede = ' var sede = new google.maps.Marker({
							position: new google.maps.LatLng('.$coords['lat'].','.$coords['lon'].'),
							map: map,
							fontSize: 35,
							align: "right",
							animation: google.maps.Animation.DROP,
							icon: "/resources/imagens/mini/home.png"
						});
						
					
					markers.push(sede);';
		}

		//marca coordenadas das unidades preenchida na proposta
		$unidades = $Proposta->itens_segurados();
		$i = 1;
		$showSede = true;
		foreach ($unidades as $item) {
			if (!empty($item['is_coordenadas_geograficas'])) {
				$coords = Agro_Util::coordenadas($item['is_coordenadas_geograficas']);

				$desc = $item['is_descricao_item'];

				if ($item['is_coordenadas_geograficas'] == $coord_talhao_sede) {
					$showSede = false;
					$desc = $item['is_descricao_item'].' (sede)';
				}

				$pinsCoords .= 'marker'.$i.' = new google.maps.Marker({
												position: new google.maps.LatLng('.$coords['lat'].','.$coords['lon'].'),
												map: map,
												fontSize: 35,
												align: "right",
												animation: google.maps.Animation.DROP,
											});
											
											marker'.$i.'.addListener("click", function() {
												info("'.$desc.'", marker'.$i.');
											});

								markers.push(marker'.$i.');';

				$i++;
			}

			$itens[$item['id']]['is_descricao_item'] = $item['is_descricao_item'];
			$itens[$item['id']]['id_item'] = $item['id'];
		}
		
		return $itens;
	}

	private function assembleQuadras(array $quadras, ?bool $isPastagem=false): string {
		$i = 1;
		$js_pols = '';
        $js_pols .= "let coordenadas = []; ";
        $js_pols .= "let coordenadasCentroide = null; ";
        $js_pols .= "let vertices; ";

		foreach ($quadras as $quadra) {
			$paths = str_replace('latitude','lat',$quadra['ds_coordenadas']);
			$paths = str_replace('longitude','lng',$paths);
			$paths = str_replace('"','',$paths);
			
			$quadra['id_item'] = ($quadra['ds_item_segurado'] ? $quadra['ds_item_segurado'] : null);

			$js_pols .= "var pol_{$i} = new google.maps.Polygon ({ ";
			$js_pols .= "	 paths: {$paths}, ";
			$js_pols .= "	 strokeColor: 'yellow', ";
			$js_pols .= "	 editable: false, ";
			$js_pols .= "	 draggable: false, ";
			$js_pols .= "	 fillOpacity: 0.5 ";
			$js_pols .= "}); ";
			$js_pols .= "coordenadas = []; ";
			$js_pols .= "vertices = pol_{$i}.getPath(); ";
			$js_pols .= "for(let contador = 0; contador < vertices.length; contador++) { ";
			$js_pols .= "  coordenadas.push(vertices.getAt(contador).lat() + ' ' + vertices.getAt(contador).lng()); ";
			$js_pols .= "} ";
			$js_pols .= "coordenadas.push(coordenadas[0]); ";
			$js_pols .= "$.when( ";
            $js_pols .= "  $.ajax({ ";
            $js_pols .= "    type: 'POST', ";
            $js_pols .= "    url: '/seguro/croqui/buscacentroide', ";
            $js_pols .= "    dataType: 'json', ";
            $js_pols .= "    data: {coordenadas: coordenadas}, ";
            $js_pols .= "    success: function(data) { ";
            $js_pols .= "      coordenadasCentroide = data; ";
            $js_pols .= "    } ";
            $js_pols .= "  }) ";
            $js_pols .= ").then( function (data, status, xhr) { ";
			$js_pols .= "  var label_{$i} = centerLabel(coordenadasCentroide, '{$quadra['ds_nome']}'); ";
			$js_pols .= "  label_{$i}.setMap(map); ";
			$js_pols .= "  pol_{$i}.setMap(map); ";
			$js_pols .= "  talhao = new Object(); ";
			$js_pols .= "  talhao.pol = pol_{$i}; ";
			$js_pols .= "  talhao.info = label_{$i}; ";
			$js_pols .= "  talhao.id_item = '{$quadra['id_item']}'; ";
			$js_pols .= "  polygonArray.push(talhao); ";

			$idsItem = explode(",", $quadra['ds_item_segurado']);
			foreach ($idsItem as $idItem) {
				if (!empty($idItem)) {
					$js_pols .= "  itensOpcoesSelecionadas.push('{$idItem}'); ";
				}
			}

			$js_pols .= "  google.maps.event.addListener(pol_{$i}, 'click', function(e) { ";
			$js_pols .= "  	if (e.vertex !== undefined) { ";
			$js_pols .= "  		if (pol_{$i}.type === google.maps.drawing.OverayType.POLYGON) { ";
			$js_pols .= "  			var path = pol_{$i}.getPaths().getAt(e.path); ";
			$js_pols .= "  			path.removeAt(e.vertex); ";
			$js_pols .= "  			if (path.length > 3) { ";
			$js_pols .= "  				pol_{$i}.setMap(null); ";
			$js_pols .= "  			} ";
			$js_pols .= "  		} ";
			$js_pols .= "  	} ";
			$js_pols .= "  	setSelection(pol_{$i}); ";
			$js_pols .= "  }); ";
			$js_pols .= "  toolTip(pol_{$i}, 'Area: ' + getArea(pol_{$i}) + 'ha'); ";
            $js_pols .= "}); ";

			if (!$isPastagem) {
				$js_pols .= "google.maps.event.addListener(pol_$i, 'rightclick', function(e) {" .
					"for (var i=0; polygonArray.length > i; i++) {" .
						"if (polygonArray[i].pol == pol_$i) {" .
							"nomearItem(i, String(polygonArray[i].id_item)); " .
						"}" .
					"}" .
				"});";
			}

			$i++;
		}

		return $js_pols ? $js_pols : '';
	}

	public function exportarAction() {
		$this->getHelper('layout')->disableLayout();
		$this->view->croqui = json_decode($this->getRequest()->getParam('croqui'), true);
		$this->getResponse()->sendResponse();
		return false;
	}

	public function importarAction() {
		$this->isAjax();

		$Adapter = new Zend_File_Transfer_Adapter_Http();
		$Adapter->setDestination(APPLICATION_PATH.'/upload_files/temp/');
		$file = $Adapter->getFileInfo();
		$result = array('status' => false, 'message' => null);

		if(!$Adapter->receive($file['imported_croqui']['name'])) {
			$result['status'] = 'Erro ao importar arquivo KML.';
		} else {
			$extensao = explode('.',$file['imported_croqui']['name']);

			if(strtolower($extensao[1]) == strtolower('kml')){
				$dom = new DOMDocument;
				$dom->loadXML(file_get_contents(APPLICATION_PATH.'/upload_files/temp/' . $file['imported_croqui']['name'], "r"));
				$xml = simplexml_import_dom($dom);

 				if (isset($xml->Document->Placemark)) {
					$Pols = $this->importaCroqui($xml->Document->Placemark);
				} elseif (isset($xml->Folder->Document->Placemark)) {
					$Pols = $this->importaCroqui($xml->Folder->Document->Placemark); 
				} elseif (isset($xml->Document->Folder->Placemark)) {
					$Pols = $this->importaCroqui($xml->Document->Folder->Placemark); 
				} else {
					$result['message'] = 'Não foi possível importar o arquivo selecionado.';
				}
				if (is_array($Pols)) {
					$i = 1;
					$modelProposta = new Seguro_Model_Propostas();
					$Proposta = $modelProposta->find($this->getRequest()->getParam('id_proposta'))->current();
					$coords = Agro_Util::coordenadas($Proposta->propriedade()['ds_coordenadas']);

					$itens = $this->assembleSede($Proposta, $pins_coords, $sede, $showSede);

					foreach ($itens as $item1) {
    					foreach ($Pols as &$item2) {
        					if ($item1['is_descricao_item'] === $item2['ds_nome']) {
            					$item2['id_item'] = $item1['id_item'];
        					}
    					}
					}
					unset($item2);

					$result['js_pols'] = $this->assembleQuadras($Pols);
					
					$result['centro'] = 'map.setCenter(new google.maps.LatLng('.$coords['lat'].','.$coords['lon'].'));';
					$result['pins_coords'] = $pins_coords;
					if ($showSede) $result['sede'] = $sede;

                    $result['coordenadas_padrao'] = null;

					if (!empty($Pols[0]['array_coordenadas'][0])) {
					    $arrayCoordenadas = explode(',', $Pols[0]['array_coordenadas'][0]);

                        $result['coordenadas_padrao'] = [
                          'longitude' => $arrayCoordenadas[0],
                          'latitude' => $arrayCoordenadas[1],
                        ];

                        $result['centro'] = 'map.setCenter(new google.maps.LatLng('.$arrayCoordenadas[1].','.$arrayCoordenadas[0].'));';
                    }

					$result['message'] = 'Importação efetuada com sucesso.';
					$result['status'] = true;
				} else {
					$result['message'] = 'Erro na importação.';
				}
			} else {
				$result['message'] = 'Arquivo incompatível, utilizar somente extensão KML.';
				$result['status'] = false;
			}
		}

		$this->getResponse()->setBody(Zend_Json::encode($result));

		//return false;
	}

	private function importaCroqui(object $placemarks): array {
		$return = array();

		foreach($placemarks as $place) {
			//informação de poligonos
			if (isset($place->Polygon)) {
				$arCoords = array();

				if (!empty($place->name)) {
				    $quadra['ds_nome'] = (string) $place->name[0];
                }

				$coords = explode(' ',trim(preg_replace('/\s+/S', ' ', $place->Polygon->outerBoundaryIs->LinearRing->coordinates)));

				foreach($coords as $coord) {
					list($lng, $lat, $nulo) = explode(',', $coord);
					array_push($arCoords, '{lat:' . $lat . ',lng:' . $lng . '}');
				}
				
				$quadra['array_coordenadas'] = $coords;
				$quadra['ds_coordenadas'] = '[' . implode(',', $arCoords) . ']';

			} elseif (isset($place->Point)) {
                if (!empty($place->name)) {
                    $quadra['ds_nome'] = (string) $place->name[0];
                }

				continue;
			} else { continue; }

			if (is_array($quadra)) {
				array_push($return, $quadra);
				$quadra = array();
			}
		}

		return $return;
	}

	// caso já exista um croqui georeferenciado, apaga o arquivo e os registro do croqui anterior
	private function removeCroquiGeo($id_proposta) {
		$PropostaArquivos = new Seguro_Model_PropostasArquivos();
		$PropostasCroquis = new Seguro_Model_PropostasCroquis();

		$ds_nome_arquivo = $PropostasCroquis->getNomeArquivoCroqui($id_proposta);

		if ($ds_nome_arquivo != null) { 
			$return = $PropostaArquivos->deleteCroquisName($ds_nome_arquivo, $id_proposta);
			if ($return) { 
				list($nome, $id_proposta_arquivo, $data) = explode('_', $ds_nome_arquivo);
				
				if ($id_proposta_arquivo == $id_proposta) {
					$sanitizedPath = realpath(PATH_CROQUI . '/' .$ds_nome_arquivo);

					if (file_exists($sanitizedPath)) {
						unlink($sanitizedPath);
					}
				}
			}
		}

		return $return;
	}

	public function salvardesenhoAction() {
		
		$this->getHelper('ViewRenderer')->setNoRender();
		$this->getHelper('layout')->disableLayout();
		$return = array();
		$motivo = '';
		$PropostaArquivos = new Seguro_Model_PropostasArquivos();
		$PropostasCroquis = new Seguro_Model_PropostasCroquis();
		$ItensSeguradosComplementos = new Seguro_Model_ItensSeguradosComplementos();
		$Atributogrupos = new Produto_Model_Atributogrupos();
		$Propostas = new Seguro_Model_Propostas();
		$modelItensSegurados = new Seguro_Model_ItensSegurados();
		$modelCroquisTalhoes = new Seguro_Model_PropostasCroquisTalhoes();

		$proposta = $Propostas->fetchRow('id = '.$this->getRequest()->getParam('id_proposta'));
		$arCroquis = json_decode($this->getRequest()->getParam('json_croqui'), true);

		if (count($arCroquis) > 0) {

			Agro_Db_Table_Abstract::getDefaultAdapter()->beginTransaction();

			if (($this->getRequest()->getParam('id_solicitacao') == '') && ($this->getRequest()->getParam('id_laudo') == '')) {

				$resImg = $this->salvaImagemCroqui(
					$this->getRequest()->getParam('img_croqui'),
					$this->getRequest()->getParam('id_proposta'),
					$name
				);
				
				if ($resImg === true) {
					try {

						$this->removeCroquiGeo($this->getRequest()->getParam('id_proposta')); 

						$croquis = $PropostasCroquis->getCroquis($this->getRequest()->getParam('id_proposta'));

						if ((count($croquis)<=0) || isRenovacao){
							$PropostaArquivos->save($name, $this->getRequest()->getParam('id_proposta'));
							$dados['fl_vigente'] = 'true';
						} else {
							$dados['fl_vigente'] = 'false';
						}

						$PropostasCroquis->update(array('fl_vigente' => 'f'), 'id_proposta = '.$this->getRequest()->getParam('id_proposta'));

						$dados['id_proposta'] = $this->getRequest()->getParam('id_proposta');
						$dados['ds_nome_arquivo'] = $name;

						$id_croqui = $PropostasCroquis->save($dados);

						if ($id_croqui > 0) {
							$PropostasCroquisTalhoes = new Seguro_Model_PropostasCroquisTalhoes();

							$itens = $modelItensSegurados->buscarDadosItensSeguradosTalhoes(
								['sis.id'],
								[
									'sp.id = '.$this->getRequest()->getParam('id_proposta')
								]
							);
							
							$mapIdItemCentroide = [];

							foreach ($itens as $item) {
								$aux = explode(', ', $item['ds_coordenadas_centroide']);

								$mapIdItemCentroide[$item['id']]['lat'] = trim($aux[0]);
								$mapIdItemCentroide[$item['id']]['long'] = trim($aux[1]);
							}

							foreach($arCroquis as $croqui) {
								
								$dados['ds_nome'] = $croqui['info'];
								$dados['ds_coordenadas'] = json_encode($croqui['coords']);
								$dados['fl_area'] = $croqui['area'];
								$dados['id_croqui'] = $id_croqui;
								$dados['ds_item_segurado'] = $croqui['id_item'];

                                $coordenadasCalculoCentroide = array_map(function($coordenadas) {
                                   return "{$coordenadas['latitude']} {$coordenadas['longitude']}";
                                }, $croqui['coords']);

                                $coordenadasCalculoCentroide[] = "{$croqui['coords'][0]['latitude']} {$croqui['coords'][0]['longitude']}";
                                $centroide = $PropostasCroquisTalhoes->getCentroide($coordenadasCalculoCentroide);
								
                                $dados['ds_coordenadas_centroide'] = "{$centroide[0]}, {$centroide[1]}";
								
								$PropostasCroquisTalhoes->save($dados);

								$atributos = $Atributogrupos->getAtributosProposta($proposta, 'UNIDADE_SEGURADA');

								$atributoCoordenadas = array_filter($atributos, fn($a) => $a['ds_chave_rn'] === 'IS_COORDENADAS_GEOGRAFICAS');
							
								if(!empty($atributoCoordenadas)){
									list($latitudeDecimal, $longitudeDecimal) = $centroide;
									$centroideDMS = [
    									$this->decimalParaDMS($latitudeDecimal),
    									$this->decimalParaDMS($longitudeDecimal)
									];
									$idItemSegurado = $dados['ds_item_segurado'];
									
									if (filter_var($idItemSegurado, FILTER_VALIDATE_INT) !== false) {
   										$ItensSeguradosComplementos->setCoordenadas($idItemSegurado, $centroideDMS);
									} else {
   										throw new Exception('Erro ao salvar croqui. Um dos talhões não foi vinculado a um item.');
									}
								}

								$idsItensSegurados = explode(",", $dados['ds_item_segurado']);

								$modelItensSeguradosCAR = new Seguro_Model_ItensSeguradosCAR();
								$resultadoFind = (new Seguro_Model_CAR())->find($centroide[0], $centroide[1]);

								$configuracaoCarAtiva = (new Produto_Model_Atributogrupos())
									->isAtributoLiberadoParaProduto($proposta->id_produto, 'IS_CAR');
								
								foreach ($idsItensSegurados as $idItemSegurado) {
									if (empty($idItemSegurado) || !filter_var($idItemSegurado, FILTER_VALIDATE_INT)) {
										throw new Exception('Erro ao salvar croqui. Um dos talhões não foi vinculado a um item.');
									}
									
									if (array_key_exists($idItemSegurado, $mapIdItemCentroide)) {
										$centroidesIguais = $modelCroquisTalhoes->centroidesIguais(
											$mapIdItemCentroide[$idItemSegurado]['lat'],
											$mapIdItemCentroide[$idItemSegurado]['long'],
											$centroide[0],
											$centroide[1]
										);

										// Deleta apenas se houve alteração no centroide
										if (!$centroidesIguais) {
											$modelItensSeguradosCAR->deleteByItemSegurado($idItemSegurado);
										} else{
											continue;
										}
									}

									if (!empty($resultadoFind['resultado'])) {
										$mapeiaCarsSelecionadosPorItem = [];

										foreach ($resultadoFind['resultado'] as $resultado) {
											$dadosItensSeguradosCAR = [
												'id_item_segurado' => $idItemSegurado,
												'id_car' => $resultado['id'],
												'ds_car' => $resultado['cod_imovel'],
												'ds_status_imovel' => $resultado['status_imovel'],
												'vl_area' => $resultado['area'],
												'ds_condicao' => $resultado['condicao'],
												'ds_uf' => $resultado['uf'],
												'ds_municipio' => $resultado['municipio'],
												'ds_tipo_imovel' => $resultado['tipo_imovel'],
											];

											// Seta flag de CAR selecionado para o primeiro CAR encontrado para o item caso configuração do CAR não esteja ativa
											if (
												!$configuracaoCarAtiva
												&& !array_key_exists($idItemSegurado, $mapeiaCarsSelecionadosPorItem)
											) {
												$mapeiaCarsSelecionadosPorItem[$idItemSegurado] = true;
												$dadosItensSeguradosCAR['fl_selecionado'] = true;
											}

											$idItenSeguradoCAR = $modelItensSeguradosCAR->save($dadosItensSeguradosCAR);
											if (!$idItenSeguradoCAR) {
												throw new Exception("Erro ao salvar os dados do CAR do item {$dados['ds_nome']}");
											}
										}
									}
								}
							}
							
						} else {
							//todo remover o delete pois agora tem rollback
							$PropostaArquivos->deleteCroquis($this->getRequest()->getParam('id_proposta'));
							throw new Exception('Erro ao salvar coordenadas do Croqui.');
							Agro_Db_Table_Abstract::getDefaultAdapter()->rollback();
						}

						if (!$PropostasCroquisTalhoes->verificaItemCroqui($dados['id_proposta'], $id_croqui, $motivo)) {
							$sanitizedPath = realpath(PATH_CROQUI . '/' . $name);

							if (file_exists($sanitizedPath)) {
								unlink($sanitizedPath);
							}

							if ($motivo == 'ITEM') {
								$msg = 'Existe(m) item(s) da proposta não marcado(s) nos polígonos do croqui.';
							} else {
								$msg = 'Existe(m) polígono(s) sem vínculo com algum item declarado na proposta.';
							}
							$return['message'] = 'Erro: '.$msg;
							$return['status'] = false;
							throw new Exception('Erro: '.$msg);
							Agro_Db_Table_Abstract::getDefaultAdapter()->rollback();
						}
						
						if (!$proposta->isEndosso()) {
							$hash = (new Seguro_Model_PropostasHashOrcamento())->save($this->getRequest()->getParam('id_proposta'));
							if (!$hash) {
								throw new Exception("Não foi possível criar a hash do orçamento.");
							}
						}
						
						$return['message'] = 'Croqui salvo com sucesso.';
						$return['status'] = true;
						Agro_Db_Table_Abstract::getDefaultAdapter()->commit();

					} catch (Exception $e) {
						$sanitizedPath = realpath(PATH_CROQUI . '/' . $name);

						if (file_exists($sanitizedPath)) {
							unlink($sanitizedPath);
						}

						$return['message'] = $e->getMessage();
						$return['status'] = false;
						Agro_Db_Table_Abstract::getDefaultAdapter()->rollback();
					}
				} else {
					$return['message'] = $resImg;
					$return['status'] = false;
					Agro_Db_Table_Abstract::getDefaultAdapter()->rollback();
				}
			} elseif ($this->getRequest()->getParam('id_solicitacao')) {
				$dados = array();
				$SolicitacaoCroqui = new Endosso_Model_SolicitacaoCroqui();
				$Solicitacao = new Endosso_Model_SolicitacaoArquivos();
				$RowSolicitacaoCroqui = $SolicitacaoCroqui->getCroquiSolicitacao($this->getRequest()->getParam('id_solicitacao'));

				if ($RowSolicitacaoCroqui->ds_nome_arquivo) {
					$sanitizedPath = realpath(APPLICATION_PATH . '/upload_files/solicitacoes/' . $RowSolicitacaoCroqui->ds_nome_arquivo);

					if (file_exists($sanitizedPath)) {
						unlink($sanitizedPath);
					}

					$Solicitacao->delete($RowSolicitacaoCroqui->id_solicitacao_arquivo);
					$SolicitacaoCroqui->delete($RowSolicitacaoCroqui->id_solicitacao_croqui);
					$PropostasCroquis->delete($RowSolicitacaoCroqui->id_croqui);
				}
				
				$resImg = $this->salvaImagemCroquiSolicitacao($this->getRequest()->getParam('img_croqui'), 
					$this->getRequest()->getParam('id_proposta'), $this->getRequest()->getParam('id_solicitacao'), $name);

				if ($resImg === true) {
					try {

						$Row = $Solicitacao->createRow();
						$Row->id_solicitacao = $this->getRequest()->getParam('id_solicitacao');
						$Row->fl_assinatura = 'false';
						$Row->ds_nome_arquivo = $name;
						$Row->fl_geocroqui = 'true';

						if ($Row->save()) {
							$dados['id_proposta'] = $this->getRequest()->getParam('id_proposta');
							$dados['ds_nome_arquivo'] = $name;
							$dados['fl_vigente'] = 'false';

							$id_croqui = $PropostasCroquis->save($dados);
							if ($id_croqui > 0) {
								$PropostasCroquisTalhoes = new Seguro_Model_PropostasCroquisTalhoes();
								foreach($arCroquis as $croqui) {
									$dados['ds_nome'] = $croqui['info'];
									$dados['ds_coordenadas'] = json_encode($croqui['coords']);
									$dados['fl_area'] = $croqui['area'];
									$dados['id_croqui'] = $id_croqui;
									$dados['ds_item_segurado'] = $croqui['id_item'];
									$PropostasCroquisTalhoes->save($dados);	
								}
								
								$Tupla = $SolicitacaoCroqui->createRow();
								$Tupla->id_solicitacao = $this->getRequest()->getParam('id_solicitacao');
								$Tupla->id_croqui = $id_croqui;
								$Tupla->save();
							} else {
								Agro_Db_Table_Abstract::getDefaultAdapter()->rollback();

								$sanitizedPath = realpath(APPLICATION_PATH . '/upload_files/solicitacoes/' . $name);

								if (file_exists($sanitizedPath)) {
									unlink($sanitizedPath);
								}

								$return['message'] = 'Erro ao salvar coordenadas do croqui.';
								$return['status'] = false; 
								throw new Exception('Erro ao salvar coordenadas do croqui.');
							}

							if ($PropostasCroquisTalhoes->verificaItemCroquiSolicitacao($dados['id_proposta'], $id_croqui) == false) {
                                Agro_Db_Table_Abstract::getDefaultAdapter()->rollback();

								$sanitizedPath = realpath(APPLICATION_PATH . '/upload_files/solicitacoes/' . $name);

								if (file_exists($sanitizedPath)) {
									unlink($sanitizedPath);
								}

                                $mensagem = "ATENÇÃO\nÉ necessário vincular todos os itens/polígonos para salvar o croqui georreferenciado.";
                                $return['message'] = $mensagem;
                                $return['status'] = false;
                                throw new Exception($mensagem);
                            }

                            $modelSolicitacao = new Endosso_Model_Solicitacao();
							$rowSolicitacao = $modelSolicitacao->getRow($this->getRequest()->getParam('id_solicitacao'));

							if ($rowSolicitacao['id_status'] === Sistema_Model_Status::SOLICITACAO_ENDOSSO_PENDENTE) {
                                $rowSolicitacao['id_status'] = Sistema_Model_Status::SOLICITACAO_ENDOSSO_NAO_ANALISADO;
                                $rowSolicitacao->save();
                            }
							
							Agro_Db_Table_Abstract::getDefaultAdapter()->commit();
							$return['message'] = 'Croqui salvo com sucesso.';
							$return['status'] = true;
						}
					} catch (Exception $e) {
						$sanitizedPath = realpath(APPLICATION_PATH . '/upload_files/solicitacoes/' . $name);

						if (file_exists($sanitizedPath)) {
							unlink($sanitizedPath);
						}

						$return['message'] = $e->getMessage();
						$return['status'] = false;
					}
				}
			} elseif ($this->getRequest()->getParam('id_laudo')) {
				// croqui aberto na tela do laudo de vistoria previa
				$Croquis = new Regulacao_Model_Croquis();

				$croqui = $Croquis->fetchAll("id_laudo = {$this->getRequest()->getParam('id_laudo')}")->toArray();
				if ($croqui[0]['ds_nome_arquivo']) {
					$sanitizedPath = realpath(APPLICATION_PATH . '/upload_files/regulacao/' . $croqui->ds_nome_arquivo);

					if (file_exists($sanitizedPath)) {
						unlink($sanitizedPath);
					}

					$dadosCroqui['id'] = $croqui[0]['id'];
				}

				$resImg = $this->salvaImagemCroquiLaudo($this->getRequest()->getParam('img_croqui'), 
					$this->getRequest()->getParam('id_proposta'), $this->getRequest()->getParam('id_laudo'), $name);

				if ($resImg === true) {

					try {
						$dadosCroqui['id_laudo'] = $this->getRequest()->getParam('id_laudo');
						$dadosCroqui['ds_referencia_regulacao'] = $this->getRequest()->getParam('nome_regulacao');
						$dadosCroqui['ds_nome_arquivo'] = $name;

						$id_croqui = $Croquis->save($dadosCroqui);
						if ($id_croqui > 0) {
							$CroquisTalhoes = new Regulacao_Model_CroquisTalhoes();
							$CroquisTalhoes->deleteByIdCroqui($id_croqui);
							foreach($arCroquis as $cr) {
								$dados['id_croqui'] = $id_croqui;
								$dados['ds_nome'] = $cr['info'];
								$dados['fl_area'] = $cr['area'];
								$dados['ds_coordenadas'] = json_encode($cr['coords']);
								$dados['ds_item_segurado'] = $cr['id_item'];
								$CroquisTalhoes->save($dados);
								$dados = array();
							}
						}

						$id_proposta_vistoria = (new Regulacao_Model_Lvp001())->fetchRow("id = " . $this->getRequest()->getParam('id_laudo'))->id_proposta_vistoria;

						$VPArquivos = new Seguro_Model_Vistoriapreviaempresaarquivos();
						$dados = array(
							'ds_nome_arquivo' => $name,
							'id_tipo_arquivo_laudo_previa' => 1,
							'id_proposta_vistoria' => $id_proposta_vistoria,
							'id' => $VPArquivos->fetchRow("id_proposta_vistoria = " . $id_proposta_vistoria . " and ds_nome_arquivo = '" . $name . "'")->id
						);
						
						$VPArquivos->save($dados);

						Agro_Db_Table_Abstract::getDefaultAdapter()->commit();
						$return['message'] = 'Croqui salvo com sucesso.';
						$return['status'] = true;	

					} catch (Exception $e) {
						$return['message'] = $e->getMessage();
						$return['status'] = false;

						$sanitizedPath = realpath(APPLICATION_PATH . '/upload_files/regulacao/' . $name);

						if (file_exists($sanitizedPath)) {
							unlink($sanitizedPath);
						}

						Agro_Db_Table_Abstract::getDefaultAdapter()->rollback();
					}
				} else {
					$return['message'] = $resImg;
					$return['status'] = false; Agro_Util::zf_debug($return);
				}
			}
		} else {
			$return['message'] = 'Atenção: É necessário ao menos uma quadra desenhada.';
			$return['status'] = false;
		}

		$this->getResponse()->setBody(Zend_Json::encode($return));
	}

	// Cria uma imagem png do mapa georeferenciado que está na tela
	private function salvaImagemCroqui($base64croqui,$id_proposta, &$filename) {
	
		$base = explode(',', $base64croqui);

		try {
			if (!base64_decode($base[1], true)) {
				throw new Exception("Erro: Croqui não é uma imagem válida.");
			}

			$filename = 'CROQUI_' . $id_proposta . '_' . date('Whis').'.png';
			$fullname = PATH_CROQUI.'/'.$filename;

			if (imagejpeg(imagecreatefromstring(base64_decode($base[1])), $fullname, 70)) {
				return true;
			} else {
				throw new Exception('Não foi possível criar imagem de croqui.');
			}

		} catch (Exception $e) {
			return $e->getMessage();
		}		
	}

	private function salvaImagemCroquiSolicitacao($base64croqui, $id_proposta, $id_solicitacao, &$filename) {
		$base = explode(',', $base64croqui);
		try {
			if (!base64_decode($base[1], true)) {
				throw new Exception("Erro: Croqui não é uma imagem válida.");
			}

			$filename = 'Solicitacao_Endosso_Complementar_' . $id_solicitacao . '_' . date('YmdHms') . '_' . $id_proposta . '.png';
			$fullname = APPLICATION_PATH . '/upload_files/solicitacoes/' . $filename;

			if (imagejpeg(imagecreatefromstring(base64_decode($base[1])), $fullname, 70)) {
				return true;
			} else {
				throw new Exception('Não foi possível criar imagem de croqui.');
			}
		} catch (Exception $e) {
			return $e->getMessage();
		}
	}

	private function salvaImagemCroquiLaudo($base64croqui, $id_proposta, $id_laudo, &$filename) {
		$base = explode(',', $base64croqui);

		try {
			if (!base64_decode($base[1], true)) {
				throw new Exception("Erro: Croqui não é uma imagem válida.");
			}

			$filename = $id_proposta . '_VP_' . $id_laudo . '.png';
			$fullname = APPLICATION_PATH . '/upload_files/laudoprevia/' . $filename;

			if (imagejpeg(imagecreatefromstring(base64_decode($base[1])), $fullname, 70)) {
				return true;
			} else {
				throw new Exception('Não foi possível criar imagem de croqui.');
			}
		} catch (Exception $e) {
			return $e->getMessage();
		}
	}

	public function buscarprodutividadeAction()
	{
		$this->isAjax();
		$return = ['status'=> true, 'message' => '', 'dados' => []];

		try {
			$params = $this->getRequest()->getParams();
			if (empty($params['id_proposta'])) {
				throw new Exception("ID da proposta não informado.");
			}
			
			$dados = [];

			if ((new Seguro_Model_Propostas())->hasProdutividadePorItemConfigurada((int) $params['id_proposta'])) {
				$dados = $this->getOrcamentoProdutividadeItem((int) $params['id_proposta']);
			}
			
			if (empty($dados)) {
				$dados = $this->getProdutividadeEstimadaCAR((int) $params['id_proposta']);
			}

			$return['dados'] = $dados;
		} catch (\Throwable $th) {
			$return['message'] = $th->getMessage();
			$return['status'] = false;
		}

		$this->getResponse()->setBody(Zend_Json::encode($return));
	}

	private function getOrcamentoProdutividadeItem(int $idProposta): array
	{
		$taxasPEItem = (new Comercializacao_Model_TaxaAgrupamentoOrcamentoItem())
			->findByIdProposta($idProposta);
		
		$dados = [];
		foreach ($taxasPEItem as $taxa) {
			$dados[] = [
				'nr_item_segurado' => $taxa['nr_item_segurado'],
				'vl_produtividade' => $taxa['vl_produtividade_estimada']
			];
		}

		return $dados;
	}

	private function getProdutividadeEstimadaCAR(int $idProposta): array
	{
		$modelPropostas = new Seguro_Model_Propostas();
		$proposta = $modelPropostas->find($idProposta)->current();

		$produtividadeEstimada = $proposta->produtividade_estimada();
		$vlProdutividadePadrao = null;
		
		if ($produtividadeEstimada != false) {
			$vlProdutividadePadrao = $produtividadeEstimada;
		}

		$modelItensSeguradosCAR = new Seguro_Model_ItensSeguradosCAR();
		$itensSeguradosCAR = $modelItensSeguradosCAR->getCarAgrupadosPorItemByProposta($proposta['id']);
		
		$dados = [];
		foreach ($itensSeguradosCAR as $itemSeguradoCAR) {
			if (!empty($itemSeguradoCAR['cars'])) {
				$cars = explode(',', $itemSeguradoCAR['cars']);
				$vlProdutividade = '';
				$taxasCar = (new Comercializacao_Model_TaxasAgrupamentoCar())
					->getTaxaAgrupamentoByCARS((int) $proposta['id_produto'], $cars);
				
				if (!empty($taxasCar)) {
					if (count($taxasCar) > 1) {
						throw new Exception("Erro de coordenada. Favor entrar em contato com a AgroBrasil.");
					}
					$vlProdutividade = $taxasCar[0]['vl_produtividade_esperada'];
				}
			}

			$dados[] = [
				'nr_item_segurado' => $itemSeguradoCAR['nr_item_segurado'],
				'vl_produtividade' => $vlProdutividade ? $vlProdutividade : $vlProdutividadePadrao
			];
		}

		return $dados;
	}
	
    public function buscacentroideAction()
    {
        $this->isAjax();

        $retorno = (new Seguro_Model_PropostasCroquisTalhoes())->getCentroide($this->getRequest()->getParam('coordenadas'));

        if (empty($retorno)) {
            $this->getResponse()->setBody(Zend_Json::encode([]));
            return;
        }

        $this->getResponse()->setBody(Zend_Json::encode($retorno));
    }

	/**
 	* Converte uma coordenada decimal para o formato DMS (graus, minutos, segundos).
 	*
 	* Este método recebe um valor decimal (latitude ou longitude) e o converte
 	* para uma string formatada no padrão DMS, incluindo o sinal negativo se aplicável.
 	*
 	* @param float $decimal Valor decimal da coordenada.
 	* @return string Coordenada formatada em DMS (ex: "-23 34 45").
 	*/
	private function decimalParaDMS($decimal) {
		$sinal = $decimal < 0 ? '-' : '';
		$decimal = abs($decimal);

		$graus = floor($decimal);
		$minutosDecimais = ($decimal - $graus) * 60;
		$minutos = floor($minutosDecimais);
		$segundos = round(($minutosDecimais - $minutos) * 60);

		return sprintf('%s%d %02d %02d', $sinal, $graus, $minutos, $segundos);
	}
}
