<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkInputPort.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "vtkInputPort.h"
#include "vtkOutputPort.h"
#include "vtkMultiProcessController.h"
#include "vtkPolyData.h"
#include "vtkUnstructuredGrid.h"
#include "vtkStructuredGrid.h"
#include "vtkRectilinearGrid.h"
#include "vtkStructuredPoints.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkCommand.h"

//----------------------------------------------------------------------------
vtkInputPort* vtkInputPort::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkInputPort");
  if(ret)
    {
    return (vtkInputPort*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkInputPort;
}

//----------------------------------------------------------------------------
vtkInputPort::vtkInputPort()
{
  this->RemoteProcessId = 0;
  this->Tag = 0;

  // Controller keeps a reference to this object as well.
  this->Controller = NULL;
  this->SetController(vtkMultiProcessController::GetGlobalController());

  // State variables.
  this->TransferNeeded = 0;
  this->DataTime = 0;

  this->DoUpdateInformation = 1;
}

//----------------------------------------------------------------------------
// We need to have a "GetNetReferenceCount" to avoid memory leaks.
vtkInputPort::~vtkInputPort()
{
  this->SetController(0);
}

//----------------------------------------------------------------------------
void vtkInputPort::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkSource::PrintSelf(os,indent);
  os << indent << "RemoteProcessId: " << this->RemoteProcessId << endl;
  os << indent << "Tag: " << this->Tag << endl;
  os << indent << "Controller: (" << this->Controller << ")\n";
  os << indent << "DataTime: " << this->DataTime << endl;
  os << indent << "TransferNeeded: " << this->TransferNeeded << endl;
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkPolyData *vtkInputPort::GetPolyDataOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_POLY_DATA)
      {
      return (vtkPolyData*)(output);
      }
    else
      {
      vtkWarningMacro("vtkInputPort: Changing data type of output.");
      }
    }

  output = vtkPolyData::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkPolyData*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkUnstructuredGrid *vtkInputPort::GetUnstructuredGridOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_UNSTRUCTURED_GRID)
      {
      return (vtkUnstructuredGrid*)(output);
      }
    else
      {
      vtkWarningMacro("vtkInputPort: Changing data type of output.");
      }
    }

  output = vtkUnstructuredGrid::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkUnstructuredGrid*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkStructuredGrid *vtkInputPort::GetStructuredGridOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_STRUCTURED_GRID)
      {
      return (vtkStructuredGrid*)(output);
      }
    else
      {
      vtkWarningMacro("vtkInputPort: Changing data type of output.");
      }
    }

  output = vtkStructuredGrid::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkStructuredGrid*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkRectilinearGrid *vtkInputPort::GetRectilinearGridOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_RECTILINEAR_GRID)
      {
      return (vtkRectilinearGrid*)(output);
      }
    else
      {
      vtkWarningMacro("vtkInputPort: Changing data type of output.");
      }
    }

  output = vtkRectilinearGrid::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkRectilinearGrid*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkStructuredPoints *vtkInputPort::GetStructuredPointsOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_STRUCTURED_POINTS)
      {
      return (vtkStructuredPoints*)(output);
      }
    else
      {
      vtkWarningMacro("vtkInputPort: Changing data type of output.");
      }
    }

  output = vtkStructuredPoints::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkStructuredPoints*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkImageData *vtkInputPort::GetImageDataOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkImageData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_IMAGE_DATA)
      {
      return (vtkImageData*)(output);
      }
    else
      {
      vtkWarningMacro("vtkInputPort: Changing data type of output.");
      }
    }

  output = vtkImageData::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkImageData*)(output);
}

//----------------------------------------------------------------------------
// The only tricky thing here is the translation of the PipelineMTime
// into a value meaningful to this process.
void vtkInputPort::UpdateInformation()
{
  vtkDataObject *output;
  unsigned long pmt;

  if (!this->DoUpdateInformation)
    {
    return;
    }

  if (this->Outputs == NULL || this->Outputs[0] == NULL)
    {
    vtkErrorMacro("No output.");
    return;
    }

  output = this->Outputs[0];

  // Trigger UpdateInformation in remotePort.
  // Up-stream port should have the same tag.
  this->Controller->TriggerRMI(this->RemoteProcessId, this->Tag);

  // Now receive the information
  int wholeInformation[7];
  this->Controller->Receive( wholeInformation, 7,
                             this->RemoteProcessId,
                             vtkInputPort::INFORMATION_TRANSFER_TAG);

  this->Controller->Receive( &pmt, 1,
                             this->RemoteProcessId,
                             vtkInputPort::INFORMATION_TRANSFER_TAG);

  output->SetWholeExtent( wholeInformation );

  // Save the upstream PMT for execute check (this may not be necessary)
  this->UpStreamMTime = pmt;

  // !!! Make sure that Update is called if data is released. !!!
  if (pmt > this->DataTime || output->GetDataReleased())
    {
    // Our data is out of data.  We will need a transfer.
    // This Modified call will ensure Update will get called.
    this->Modified();
    }
  output->SetPipelineMTime(this->GetMTime());
  // Locality has to be changed too.
  output->SetLocality(1.0);

}

//----------------------------------------------------------------------------
// The only tricky thing here is the translation of the PipelineMTime
// into a value meaningful to this process.
void vtkInputPort::TriggerAsynchronousUpdate()
{
  // This should be cleared by this point.
  // UpdateInformation and Update calls need to be made in pairs.
  if (this->TransferNeeded)
    {
    vtkWarningMacro("Transfer should have been received.");
    return;
    }

  vtkDataObject *output = this->Outputs[0];

  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // This would normally be done in the Update method, but since
  // we want task parallelism with multiple input filters,
  // it needs to be here.

  // Do we need to update?
  // !!! I am uneasy about the Released check.  Although a new update extent
  // will cause the data to be released,  released data does not imply
  // Update will be called !!!!
  if (this->UpStreamMTime <= this->DataTime && ! output->GetDataReleased())
    {
    // No, we do not need to update.
    return;
    }

  // Trigger Update in remotePort.
  // remotePort should have the same tag.
  this->Controller->TriggerRMI(this->RemoteProcessId, this->Tag+1);

  // Send the UpdateExtent request. The first 6 ints are the 3d extent, the next
  // to are the pieces extent (we don't know which type it is - just send both)
  int extent[9];
  output->GetUpdateExtent( extent );
  extent[6] = output->GetUpdatePiece();
  extent[7] = output->GetUpdateNumberOfPieces();
  extent[8] = output->GetUpdateGhostLevel();
  this->Controller->Send( extent, 9, this->RemoteProcessId,
                          vtkInputPort::UPDATE_EXTENT_TAG);

  // This is for pipeline parallism.
  // The Upstream port may or may not promote its data (execute).
  // It needs the data time of our output to compare to the mtime
  // of its input to determine if it should send the data (execute).
  this->Controller->Send( &(this->DataTime), 1, this->RemoteProcessId,
			  vtkInputPort::NEW_DATA_TIME_TAG);

  // This automatically causes to remotePort to send the data.
  // Tell the update method to receive the data.
  this->TransferNeeded = 1;
}

//----------------------------------------------------------------------------
void vtkInputPort::UpdateData(vtkDataObject *output)
{

  if (this->UpStreamMTime <= this->DataTime && ! output->GetDataReleased())
    {
    // No, we do not need to update.
    return;
    }

  if ( ! this->TransferNeeded)
    {
    // If something unexpected happened, let me know.
    vtkWarningMacro("UpdateData was called when no data was needed.");
    return;
    }

  this->InvokeEvent(vtkCommand::StartEvent,NULL);

  // Well here is a bit of a hack.
  // Since the reader will overwrite whole extents, we need to save the whole
  // extent and reset it.
  int wholeExtent[6];
  output->GetWholeExtent(wholeExtent);
  // receive the data

  this->Controller->Receive(output, this->RemoteProcessId,
			    vtkInputPort::DATA_TRANSFER_TAG);

  output->SetWholeExtent( wholeExtent );

  this->InvokeEvent(vtkCommand::EndEvent,NULL);

  // Receive the data time
  this->Controller->Receive( &(this->DataTime), 1, this->RemoteProcessId,
			    vtkInputPort::NEW_DATA_TIME_TAG);

  this->TransferNeeded = 0;
}

<commit_msg>Unnecessary warnings.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkInputPort.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "vtkInputPort.h"
#include "vtkOutputPort.h"
#include "vtkMultiProcessController.h"
#include "vtkPolyData.h"
#include "vtkUnstructuredGrid.h"
#include "vtkStructuredGrid.h"
#include "vtkRectilinearGrid.h"
#include "vtkStructuredPoints.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkCommand.h"

//----------------------------------------------------------------------------
vtkInputPort* vtkInputPort::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkInputPort");
  if(ret)
    {
    return (vtkInputPort*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkInputPort;
}

//----------------------------------------------------------------------------
vtkInputPort::vtkInputPort()
{
  this->RemoteProcessId = 0;
  this->Tag = 0;

  // Controller keeps a reference to this object as well.
  this->Controller = NULL;
  this->SetController(vtkMultiProcessController::GetGlobalController());

  // State variables.
  this->TransferNeeded = 0;
  this->DataTime = 0;

  this->DoUpdateInformation = 1;
}

//----------------------------------------------------------------------------
// We need to have a "GetNetReferenceCount" to avoid memory leaks.
vtkInputPort::~vtkInputPort()
{
  this->SetController(0);
}

//----------------------------------------------------------------------------
void vtkInputPort::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkSource::PrintSelf(os,indent);
  os << indent << "RemoteProcessId: " << this->RemoteProcessId << endl;
  os << indent << "Tag: " << this->Tag << endl;
  os << indent << "Controller: (" << this->Controller << ")\n";
  os << indent << "DataTime: " << this->DataTime << endl;
  os << indent << "TransferNeeded: " << this->TransferNeeded << endl;
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkPolyData *vtkInputPort::GetPolyDataOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_POLY_DATA)
      {
      return (vtkPolyData*)(output);
      }
//      else
//        {
//        vtkWarningMacro("vtkInputPort: Changing data type of output.");
//        }
    }

  output = vtkPolyData::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkPolyData*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkUnstructuredGrid *vtkInputPort::GetUnstructuredGridOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_UNSTRUCTURED_GRID)
      {
      return (vtkUnstructuredGrid*)(output);
      }
//      else
//        {
//        vtkWarningMacro("vtkInputPort: Changing data type of output.");
//        }
    }

  output = vtkUnstructuredGrid::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkUnstructuredGrid*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkStructuredGrid *vtkInputPort::GetStructuredGridOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_STRUCTURED_GRID)
      {
      return (vtkStructuredGrid*)(output);
      }
//      else
//        {
//        vtkWarningMacro("vtkInputPort: Changing data type of output.");
//        }
    }

  output = vtkStructuredGrid::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkStructuredGrid*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkRectilinearGrid *vtkInputPort::GetRectilinearGridOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_RECTILINEAR_GRID)
      {
      return (vtkRectilinearGrid*)(output);
      }
//      else
//        {
//        vtkWarningMacro("vtkInputPort: Changing data type of output.");
//        }
    }

  output = vtkRectilinearGrid::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkRectilinearGrid*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkStructuredPoints *vtkInputPort::GetStructuredPointsOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkPolyData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_STRUCTURED_POINTS)
      {
      return (vtkStructuredPoints*)(output);
      }
//      else
//        {
//        vtkWarningMacro("vtkInputPort: Changing data type of output.");
//        }
    }

  output = vtkStructuredPoints::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkStructuredPoints*)(output);
}

//----------------------------------------------------------------------------
// Maybe we can come up with a way to check the type of the upstream port's
// input here.  While we are at it, we could automatically generate a tag.
vtkImageData *vtkInputPort::GetImageDataOutput()
{
  vtkDataObject *output = NULL;

  // If there is already an output, I hope it is a vtkImageData.
  if (this->Outputs)
    {
    output = this->Outputs[0];
    }
  if (output)
    {
    if (output->GetDataObjectType() == VTK_IMAGE_DATA)
      {
      return (vtkImageData*)(output);
      }
//      else
//        {
//        vtkWarningMacro("vtkInputPort: Changing data type of output.");
//        }
    }

  output = vtkImageData::New();
  output->ReleaseData();
  this->vtkSource::SetNthOutput(0, output);
  output->Delete();
  return (vtkImageData*)(output);
}

//----------------------------------------------------------------------------
// The only tricky thing here is the translation of the PipelineMTime
// into a value meaningful to this process.
void vtkInputPort::UpdateInformation()
{
  vtkDataObject *output;
  unsigned long pmt;

  if (!this->DoUpdateInformation)
    {
    return;
    }

  if (this->Outputs == NULL || this->Outputs[0] == NULL)
    {
    vtkErrorMacro("No output.");
    return;
    }

  output = this->Outputs[0];

  // Trigger UpdateInformation in remotePort.
  // Up-stream port should have the same tag.
  this->Controller->TriggerRMI(this->RemoteProcessId, this->Tag);

  // Now receive the information
  int wholeInformation[7];
  this->Controller->Receive( wholeInformation, 7,
                             this->RemoteProcessId,
                             vtkInputPort::INFORMATION_TRANSFER_TAG);

  this->Controller->Receive( &pmt, 1,
                             this->RemoteProcessId,
                             vtkInputPort::INFORMATION_TRANSFER_TAG);

  output->SetWholeExtent( wholeInformation );

  // Save the upstream PMT for execute check (this may not be necessary)
  this->UpStreamMTime = pmt;

  // !!! Make sure that Update is called if data is released. !!!
  if (pmt > this->DataTime || output->GetDataReleased())
    {
    // Our data is out of data.  We will need a transfer.
    // This Modified call will ensure Update will get called.
    this->Modified();
    }
  output->SetPipelineMTime(this->GetMTime());
  // Locality has to be changed too.
  output->SetLocality(1.0);

}

//----------------------------------------------------------------------------
// The only tricky thing here is the translation of the PipelineMTime
// into a value meaningful to this process.
void vtkInputPort::TriggerAsynchronousUpdate()
{
  // This should be cleared by this point.
  // UpdateInformation and Update calls need to be made in pairs.
  if (this->TransferNeeded)
    {
    vtkWarningMacro("Transfer should have been received.");
    return;
    }

  vtkDataObject *output = this->Outputs[0];

  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // This would normally be done in the Update method, but since
  // we want task parallelism with multiple input filters,
  // it needs to be here.

  // Do we need to update?
  // !!! I am uneasy about the Released check.  Although a new update extent
  // will cause the data to be released,  released data does not imply
  // Update will be called !!!!
  if (this->UpStreamMTime <= this->DataTime && ! output->GetDataReleased())
    {
    // No, we do not need to update.
    return;
    }

  // Trigger Update in remotePort.
  // remotePort should have the same tag.
  this->Controller->TriggerRMI(this->RemoteProcessId, this->Tag+1);

  // Send the UpdateExtent request. The first 6 ints are the 3d extent, the next
  // to are the pieces extent (we don't know which type it is - just send both)
  int extent[9];
  output->GetUpdateExtent( extent );
  extent[6] = output->GetUpdatePiece();
  extent[7] = output->GetUpdateNumberOfPieces();
  extent[8] = output->GetUpdateGhostLevel();
  this->Controller->Send( extent, 9, this->RemoteProcessId,
                          vtkInputPort::UPDATE_EXTENT_TAG);

  // This is for pipeline parallism.
  // The Upstream port may or may not promote its data (execute).
  // It needs the data time of our output to compare to the mtime
  // of its input to determine if it should send the data (execute).
  this->Controller->Send( &(this->DataTime), 1, this->RemoteProcessId,
			  vtkInputPort::NEW_DATA_TIME_TAG);

  // This automatically causes to remotePort to send the data.
  // Tell the update method to receive the data.
  this->TransferNeeded = 1;
}

//----------------------------------------------------------------------------
void vtkInputPort::UpdateData(vtkDataObject *output)
{

  if (this->UpStreamMTime <= this->DataTime && ! output->GetDataReleased())
    {
    // No, we do not need to update.
    return;
    }

  if ( ! this->TransferNeeded)
    {
    // If something unexpected happened, let me know.
    vtkWarningMacro("UpdateData was called when no data was needed.");
    return;
    }

  this->InvokeEvent(vtkCommand::StartEvent,NULL);

  // Well here is a bit of a hack.
  // Since the reader will overwrite whole extents, we need to save the whole
  // extent and reset it.
  int wholeExtent[6];
  output->GetWholeExtent(wholeExtent);
  // receive the data

  this->Controller->Receive(output, this->RemoteProcessId,
			    vtkInputPort::DATA_TRANSFER_TAG);

  output->SetWholeExtent( wholeExtent );

  this->InvokeEvent(vtkCommand::EndEvent,NULL);

  // Receive the data time
  this->Controller->Receive( &(this->DataTime), 1, this->RemoteProcessId,
			    vtkInputPort::NEW_DATA_TIME_TAG);

  this->TransferNeeded = 0;
}

<|endoftext|>


<commit_before>#pragma once

#include <array>
#include <memory>
#include <vector>

#include "DataSpec/DNACommon/GX.hpp"

#include "Runtime/CRandom16.hpp"
#include "Runtime/CToken.hpp"
#include "Runtime/Graphics/CLineRenderer.hpp"
#include "Runtime/Graphics/CTexture.hpp"
#include "Runtime/Graphics/Shaders/CParticleSwooshShaders.hpp"
#include "Runtime/Particle/CParticleGen.hpp"
#include "Runtime/Particle/CUVElement.hpp"

#include <zeus/CColor.hpp>
#include <zeus/CTransform.hpp>
#include <zeus/CVector3f.hpp>

namespace urde {
class CSwooshDescription;

class CParticleSwoosh : public CParticleGen {
  friend class CParticleSwooshShaders;

  struct SSwooshData {
    bool x0_active;
    float x4_leftRad;
    float x8_rightRad;
    zeus::CVector3f xc_translation;   // Updated by system's velocity sources or user code
    zeus::CVector3f x18_offset;       // Updated by POFS once per system update (also resets x24_useOffset)
    zeus::CVector3f x24_useOffset;    // Combination of POFS and NPOS, once per particle instance
    float x30_irot;                   // Rotation bias once per system update
    float x34_rotm;                   // Rotation bias once per particle instance
    zeus::CTransform x38_orientation; // Updated by user code
    int x68_frame;                    // Frame index of evaluated data
    zeus::CColor x6c_color;           // Updated by COLR
    int x70_startFrame;
    zeus::CVector3f x74_velocity;

    SSwooshData(const zeus::CVector3f& translation, const zeus::CVector3f& offset, float irot, float rotm,
                int startFrame, bool active, const zeus::CTransform& orient, const zeus::CVector3f& vel, float leftRad,
                float rightRad, const zeus::CColor& color)
    : x0_active(active)
    , x4_leftRad(leftRad)
    , x8_rightRad(rightRad)
    , xc_translation(translation)
    , x18_offset(offset)
    , x24_useOffset(offset)
    , x30_irot(irot)
    , x34_rotm(rotm)
    , x38_orientation(orient)
    , x6c_color(color)
    , x70_startFrame(startFrame)
    , x74_velocity(vel) {}
  };

  TLockedToken<CSwooshDescription> x1c_desc;
  u32 x28_curFrame = 0;
  int x2c_PSLT = 0;
  double x30_curTime = 0.0;
  zeus::CVector3f x38_translation;
  zeus::CTransform x44_orientation;
  zeus::CTransform x74_invOrientation;
  zeus::CVector3f xa4_globalTranslation;
  zeus::CTransform xb0_globalOrientation;
  zeus::CVector3f xe0_globalScale = {1.f, 1.f, 1.f};
  zeus::CTransform xec_scaleXf;
  zeus::CTransform x11c_invScaleXf;
  zeus::CVector3f x14c_localScale = {1.f, 1.f, 1.f};
  u32 x158_curParticle = 0;
  std::vector<SSwooshData> x15c_swooshes;
  std::vector<zeus::CVector3f> x16c_p0;
  std::vector<zeus::CVector3f> x17c_p1;
  std::vector<zeus::CVector3f> x18c_p2;
  std::vector<zeus::CVector3f> x19c_p3;
  u32 x1ac_particleCount = 0;
  int x1b0_SPLN = 0;
  int x1b4_LENG = 0;
  int x1b8_SIDE = 0;
  GX::Primitive x1bc_prim;
  CRandom16 x1c0_rand;
  float x1c4_ = 0.f;
  float x1c8_ = 0.f;
  float x1cc_TSPN;
  bool x1d0_24_emitting : 1;
  bool x1d0_25_AALP : 1;
  bool x1d0_26_forceOneUpdate : 1;
  bool x1d0_27_renderGaps : 1;
  bool x1d0_28_LLRD : 1;
  bool x1d0_29_VLS1 : 1;
  bool x1d0_30_VLS2 : 1;
  bool x1d0_31_constantTex : 1;
  bool x1d1_24_constantUv : 1;

  SUVElementSet x1d4_uvs = {};
  CTexture* x1e4_tex = nullptr;
  float x1e8_uvSpan = 1.f;
  int x1ec_TSPN = 0;
  zeus::CVector3f x1f0_aabbMin;
  zeus::CVector3f x1fc_aabbMax;
  float x208_maxRadius = 0.f;
  zeus::CColor x20c_moduColor = zeus::skWhite;

  std::array<boo::ObjToken<boo::IShaderDataBinding>, 2> m_dataBind;
  boo::ObjToken<boo::IGraphicsBufferD> m_vertBuf;
  boo::ObjToken<boo::IGraphicsBufferD> m_uniformBuf;
  std::unique_ptr<CLineRenderer> m_lineRenderer;
  std::vector<CParticleSwooshShaders::Vert> m_cachedVerts;

  static int g_ParticleSystemAliveCount;

  bool IsValid() const { return x1b4_LENG >= 2 && x1b8_SIDE >= 2; }
  void UpdateMaxRadius(float r);
  void UpdateBounds(const zeus::CVector3f& pos);
  float GetLeftRadius(size_t i) const;
  float GetRightRadius(size_t i) const;
  void UpdateSwooshTranslation(const zeus::CVector3f& translation);
  void UpdateTranslationAndOrientation();

  static zeus::CVector3f GetSplinePoint(const zeus::CVector3f& p0, const zeus::CVector3f& p1, const zeus::CVector3f& p2,
                                        const zeus::CVector3f& p3, float t);
  int WrapIndex(int i) const;
  void RenderNSidedSpline();
  void RenderNSidedNoSpline();
  void Render3SidedSolidSpline();
  void Render3SidedSolidNoSplineNoGaps();
  void Render2SidedSpline();
  void Render2SidedNoSplineGaps();
  void Render2SidedNoSplineNoGaps();

public:
  CParticleSwoosh(const TToken<CSwooshDescription>& desc, int);
  ~CParticleSwoosh() override;

  CSwooshDescription* GetDesc() { return x1c_desc.GetObj(); }

  bool Update(double) override;
  void Render(const CActorLights* = nullptr) override;
  void SetOrientation(const zeus::CTransform&) override;
  void SetTranslation(const zeus::CVector3f&) override;
  void SetGlobalOrientation(const zeus::CTransform&) override;
  void SetGlobalTranslation(const zeus::CVector3f&) override;
  void SetGlobalScale(const zeus::CVector3f&) override;
  void SetLocalScale(const zeus::CVector3f&) override;
  void SetParticleEmission(bool) override;
  void SetModulationColor(const zeus::CColor&) override;
  const zeus::CTransform& GetOrientation() const override;
  const zeus::CVector3f& GetTranslation() const override;
  const zeus::CTransform& GetGlobalOrientation() const override;
  const zeus::CVector3f& GetGlobalTranslation() const override;
  const zeus::CVector3f& GetGlobalScale() const override;
  const zeus::CColor& GetModulationColor() const override;
  bool IsSystemDeletable() const override;
  std::optional<zeus::CAABox> GetBounds() const override;
  u32 GetParticleCount() const override;
  bool SystemHasLight() const override;
  CLight GetLight() const override;
  bool GetParticleEmission() const override;
  void DestroyParticles() override;
  void Reset() override {}
  FourCC Get4CharId() const override { return FOURCC('SWHC'); }
  void SetRenderGaps(bool r) { x1d0_27_renderGaps = r; }

  void DoWarmupUpdate() {
    x1d0_26_forceOneUpdate = true;
    Update(0.0);
  }

  void DoElectricWarmup() {
    for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
      x1d0_26_forceOneUpdate = true;
      Update(0.0);
    }
  }

  void DoElectricCreate(const std::vector<zeus::CVector3f>& offsets) {
    u32 curIdx = x158_curParticle;
    for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
      curIdx = u32((curIdx + 1) % x15c_swooshes.size());
      x15c_swooshes[curIdx].xc_translation = offsets[i];
    }
  }

  void DoGrappleWarmup() {
    for (size_t i = 0; i < x15c_swooshes.size() - 1; ++i) {
      x1d0_26_forceOneUpdate = true;
      Update(0.0);
    }
  }

  void DoGrappleUpdate(const zeus::CVector3f& beamGunPos, const zeus::CTransform& rotation, float anglePhase,
                       float xAmplitude, float zAmplitude, const zeus::CVector3f& swooshSegDelta) {
    float rot = x15c_swooshes.back().x30_irot;
    zeus::CVector3f trans = beamGunPos;
    for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
      SSwooshData& data = x15c_swooshes[i];
      zeus::CVector3f vec;
      if (i > 0)
        vec = rotation * zeus::CVector3f(std::cos(i + anglePhase) * xAmplitude, 0.f, std::sin(float(i)) * zAmplitude);
      data.xc_translation = trans + vec;
      trans += swooshSegDelta;
      std::swap(rot, data.x30_irot);
    }
  }

  void DoSpiderBallWarmup(zeus::CVector3f& translation, const zeus::CVector3f& transInc) {
    SetOrientation(zeus::lookAt(zeus::skZero3f, transInc));
    for (int i = 0; i < 6; ++i) {
      SetTranslation(translation);
      x1d0_26_forceOneUpdate = true;
      Update(0.0);
      translation += transInc;
    }
  }
};

} // namespace urde
<commit_msg>CParticleSwoosh: Initialize x68_frame on construction<commit_after>#pragma once

#include <array>
#include <memory>
#include <vector>

#include "DataSpec/DNACommon/GX.hpp"

#include "Runtime/CRandom16.hpp"
#include "Runtime/CToken.hpp"
#include "Runtime/Graphics/CLineRenderer.hpp"
#include "Runtime/Graphics/CTexture.hpp"
#include "Runtime/Graphics/Shaders/CParticleSwooshShaders.hpp"
#include "Runtime/Particle/CParticleGen.hpp"
#include "Runtime/Particle/CUVElement.hpp"

#include <zeus/CColor.hpp>
#include <zeus/CTransform.hpp>
#include <zeus/CVector3f.hpp>

namespace urde {
class CSwooshDescription;

class CParticleSwoosh : public CParticleGen {
  friend class CParticleSwooshShaders;

  struct SSwooshData {
    bool x0_active;
    float x4_leftRad;
    float x8_rightRad;
    zeus::CVector3f xc_translation;   // Updated by system's velocity sources or user code
    zeus::CVector3f x18_offset;       // Updated by POFS once per system update (also resets x24_useOffset)
    zeus::CVector3f x24_useOffset;    // Combination of POFS and NPOS, once per particle instance
    float x30_irot;                   // Rotation bias once per system update
    float x34_rotm;                   // Rotation bias once per particle instance
    zeus::CTransform x38_orientation; // Updated by user code
    int x68_frame = 0;                // Frame index of evaluated data
    zeus::CColor x6c_color;           // Updated by COLR
    int x70_startFrame;
    zeus::CVector3f x74_velocity;

    SSwooshData(const zeus::CVector3f& translation, const zeus::CVector3f& offset, float irot, float rotm,
                int startFrame, bool active, const zeus::CTransform& orient, const zeus::CVector3f& vel, float leftRad,
                float rightRad, const zeus::CColor& color)
    : x0_active(active)
    , x4_leftRad(leftRad)
    , x8_rightRad(rightRad)
    , xc_translation(translation)
    , x18_offset(offset)
    , x24_useOffset(offset)
    , x30_irot(irot)
    , x34_rotm(rotm)
    , x38_orientation(orient)
    , x6c_color(color)
    , x70_startFrame(startFrame)
    , x74_velocity(vel) {}
  };

  TLockedToken<CSwooshDescription> x1c_desc;
  u32 x28_curFrame = 0;
  int x2c_PSLT = 0;
  double x30_curTime = 0.0;
  zeus::CVector3f x38_translation;
  zeus::CTransform x44_orientation;
  zeus::CTransform x74_invOrientation;
  zeus::CVector3f xa4_globalTranslation;
  zeus::CTransform xb0_globalOrientation;
  zeus::CVector3f xe0_globalScale = {1.f, 1.f, 1.f};
  zeus::CTransform xec_scaleXf;
  zeus::CTransform x11c_invScaleXf;
  zeus::CVector3f x14c_localScale = {1.f, 1.f, 1.f};
  u32 x158_curParticle = 0;
  std::vector<SSwooshData> x15c_swooshes;
  std::vector<zeus::CVector3f> x16c_p0;
  std::vector<zeus::CVector3f> x17c_p1;
  std::vector<zeus::CVector3f> x18c_p2;
  std::vector<zeus::CVector3f> x19c_p3;
  u32 x1ac_particleCount = 0;
  int x1b0_SPLN = 0;
  int x1b4_LENG = 0;
  int x1b8_SIDE = 0;
  GX::Primitive x1bc_prim;
  CRandom16 x1c0_rand;
  float x1c4_ = 0.f;
  float x1c8_ = 0.f;
  float x1cc_TSPN;
  bool x1d0_24_emitting : 1;
  bool x1d0_25_AALP : 1;
  bool x1d0_26_forceOneUpdate : 1;
  bool x1d0_27_renderGaps : 1;
  bool x1d0_28_LLRD : 1;
  bool x1d0_29_VLS1 : 1;
  bool x1d0_30_VLS2 : 1;
  bool x1d0_31_constantTex : 1;
  bool x1d1_24_constantUv : 1;

  SUVElementSet x1d4_uvs = {};
  CTexture* x1e4_tex = nullptr;
  float x1e8_uvSpan = 1.f;
  int x1ec_TSPN = 0;
  zeus::CVector3f x1f0_aabbMin;
  zeus::CVector3f x1fc_aabbMax;
  float x208_maxRadius = 0.f;
  zeus::CColor x20c_moduColor = zeus::skWhite;

  std::array<boo::ObjToken<boo::IShaderDataBinding>, 2> m_dataBind;
  boo::ObjToken<boo::IGraphicsBufferD> m_vertBuf;
  boo::ObjToken<boo::IGraphicsBufferD> m_uniformBuf;
  std::unique_ptr<CLineRenderer> m_lineRenderer;
  std::vector<CParticleSwooshShaders::Vert> m_cachedVerts;

  static int g_ParticleSystemAliveCount;

  bool IsValid() const { return x1b4_LENG >= 2 && x1b8_SIDE >= 2; }
  void UpdateMaxRadius(float r);
  void UpdateBounds(const zeus::CVector3f& pos);
  float GetLeftRadius(size_t i) const;
  float GetRightRadius(size_t i) const;
  void UpdateSwooshTranslation(const zeus::CVector3f& translation);
  void UpdateTranslationAndOrientation();

  static zeus::CVector3f GetSplinePoint(const zeus::CVector3f& p0, const zeus::CVector3f& p1, const zeus::CVector3f& p2,
                                        const zeus::CVector3f& p3, float t);
  int WrapIndex(int i) const;
  void RenderNSidedSpline();
  void RenderNSidedNoSpline();
  void Render3SidedSolidSpline();
  void Render3SidedSolidNoSplineNoGaps();
  void Render2SidedSpline();
  void Render2SidedNoSplineGaps();
  void Render2SidedNoSplineNoGaps();

public:
  CParticleSwoosh(const TToken<CSwooshDescription>& desc, int);
  ~CParticleSwoosh() override;

  CSwooshDescription* GetDesc() { return x1c_desc.GetObj(); }

  bool Update(double) override;
  void Render(const CActorLights* = nullptr) override;
  void SetOrientation(const zeus::CTransform&) override;
  void SetTranslation(const zeus::CVector3f&) override;
  void SetGlobalOrientation(const zeus::CTransform&) override;
  void SetGlobalTranslation(const zeus::CVector3f&) override;
  void SetGlobalScale(const zeus::CVector3f&) override;
  void SetLocalScale(const zeus::CVector3f&) override;
  void SetParticleEmission(bool) override;
  void SetModulationColor(const zeus::CColor&) override;
  const zeus::CTransform& GetOrientation() const override;
  const zeus::CVector3f& GetTranslation() const override;
  const zeus::CTransform& GetGlobalOrientation() const override;
  const zeus::CVector3f& GetGlobalTranslation() const override;
  const zeus::CVector3f& GetGlobalScale() const override;
  const zeus::CColor& GetModulationColor() const override;
  bool IsSystemDeletable() const override;
  std::optional<zeus::CAABox> GetBounds() const override;
  u32 GetParticleCount() const override;
  bool SystemHasLight() const override;
  CLight GetLight() const override;
  bool GetParticleEmission() const override;
  void DestroyParticles() override;
  void Reset() override {}
  FourCC Get4CharId() const override { return FOURCC('SWHC'); }
  void SetRenderGaps(bool r) { x1d0_27_renderGaps = r; }

  void DoWarmupUpdate() {
    x1d0_26_forceOneUpdate = true;
    Update(0.0);
  }

  void DoElectricWarmup() {
    for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
      x1d0_26_forceOneUpdate = true;
      Update(0.0);
    }
  }

  void DoElectricCreate(const std::vector<zeus::CVector3f>& offsets) {
    u32 curIdx = x158_curParticle;
    for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
      curIdx = u32((curIdx + 1) % x15c_swooshes.size());
      x15c_swooshes[curIdx].xc_translation = offsets[i];
    }
  }

  void DoGrappleWarmup() {
    for (size_t i = 0; i < x15c_swooshes.size() - 1; ++i) {
      x1d0_26_forceOneUpdate = true;
      Update(0.0);
    }
  }

  void DoGrappleUpdate(const zeus::CVector3f& beamGunPos, const zeus::CTransform& rotation, float anglePhase,
                       float xAmplitude, float zAmplitude, const zeus::CVector3f& swooshSegDelta) {
    float rot = x15c_swooshes.back().x30_irot;
    zeus::CVector3f trans = beamGunPos;
    for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
      SSwooshData& data = x15c_swooshes[i];
      zeus::CVector3f vec;
      if (i > 0)
        vec = rotation * zeus::CVector3f(std::cos(i + anglePhase) * xAmplitude, 0.f, std::sin(float(i)) * zAmplitude);
      data.xc_translation = trans + vec;
      trans += swooshSegDelta;
      std::swap(rot, data.x30_irot);
    }
  }

  void DoSpiderBallWarmup(zeus::CVector3f& translation, const zeus::CVector3f& transInc) {
    SetOrientation(zeus::lookAt(zeus::skZero3f, transInc));
    for (int i = 0; i < 6; ++i) {
      SetTranslation(translation);
      x1d0_26_forceOneUpdate = true;
      Update(0.0);
      translation += transInc;
    }
  }
};

} // namespace urde
<|endoftext|>


<commit_before>/*
Copyright(c) 2016-2017 Panos Karabelas

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

//= INCLUDES ==================
#include "ScriptInstance.h"
#include <angelscript.h>
#include "Module.h"
#include "../Core/Helper.h"
#include "../FileSystem/FileSystem.h"
#include "../Logging/Log.h"
#include "../Core/GameObject.h"
//=============================

//= NAMESPACES =====
using namespace std;
//==================

ScriptInstance::ScriptInstance()
{
	m_gameObject = nullptr;
	m_constructorFunction = nullptr;
	m_startFunction = nullptr;
	m_updateFunction = nullptr;
	m_scriptObject = nullptr;
	m_module = nullptr;
	m_scriptEngine = nullptr;
	m_isInstantiated = false;
}

ScriptInstance::~ScriptInstance()
{
	SafeRelease(m_scriptObject);

	m_gameObject = nullptr;
	m_constructorFunction = nullptr;
	m_startFunction = nullptr;
	m_updateFunction = nullptr;
	m_scriptEngine = nullptr;
	m_isInstantiated = false;
}

bool ScriptInstance::Instantiate(const string& path, GameObject* gameObject, ScriptEngine* scriptEngine)
{
	m_scriptEngine = scriptEngine;

	// Extract properties from path
	m_scriptPath = path;
	m_gameObject = gameObject;
	m_className = FileSystem::GetFileNameNoExtensionFromPath(m_scriptPath);
	m_moduleName = m_className + m_gameObject->GetID();
	m_constructorDeclaration = m_className + " @" + m_className + "(GameObject @)";

	// Instantiate the script
	m_isInstantiated = CreateScriptObject();

	return m_isInstantiated;
}

bool ScriptInstance::IsInstantiated()
{
	return m_isInstantiated;
}

string ScriptInstance::GetScriptPath()
{
	return m_scriptPath;
}

void ScriptInstance::ExecuteStart()
{
	m_scriptEngine->ExecuteCall(m_startFunction, m_scriptObject);
}

void ScriptInstance::ExecuteUpdate()
{
	m_scriptEngine->ExecuteCall(m_updateFunction, m_scriptObject);
}

bool ScriptInstance::CreateScriptObject()
{
	// create module
	m_module = make_shared<Module>(m_moduleName, m_scriptEngine);
	bool result = m_module->LoadScript(m_scriptPath);
	if (!result)
		return false;

	auto type_id = m_module->GetAsIScriptModule()->GetTypeIdByDecl(m_className.c_str());
	asITypeInfo* type = m_scriptEngine->GetAsIScriptEngine()->GetTypeInfoById(type_id);
	if (!type)
		return false;

	m_startFunction = type->GetMethodByDecl("void Start()"); // Get the Start function from the script
	m_updateFunction = type->GetMethodByDecl("void Update()"); // Get the Update function from the script
	m_constructorFunction = type->GetFactoryByDecl(m_constructorDeclaration.c_str()); // Get the constructor function from the script
	if (!m_constructorFunction)
	{
		LOG_ERROR("Couldn't find the appropriate factory for the type '" + m_className + "'");
		return false;
	}

	asIScriptContext* context = m_scriptEngine->RequestContext(); // request a context
	int r = context->Prepare(m_constructorFunction); // prepare the context to call the factory function
	if (r < 0) return false;

	r = context->SetArgObject(0, m_gameObject); // Pass the gameobject as the constructor's parameter
	if (r < 0) return false;

	r = context->Execute(); // execute the call
	if (r < 0) return false;

	// get the object that was created
	m_scriptObject = *static_cast<asIScriptObject**>(context->GetAddressOfReturnValue());

	// if you're going to store the object you must increase the reference,
	// otherwise it will be destroyed when the context is reused or destroyed.
	m_scriptObject->AddRef();

	// return context
	m_scriptEngine->ReturnContext(context);

	return true;
}
<commit_msg>Fixed a bug when upon releasing a script object, it would fail to get deleted because of an external reference to another object.<commit_after>/*
Copyright(c) 2016-2017 Panos Karabelas

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

//= INCLUDES ==================
#include "ScriptInstance.h"
#include <angelscript.h>
#include "Module.h"
#include "../Core/Helper.h"
#include "../FileSystem/FileSystem.h"
#include "../Logging/Log.h"
#include "../Core/GameObject.h"
//=============================

//= NAMESPACES =====
using namespace std;
//==================

ScriptInstance::ScriptInstance()
{
	m_gameObject = nullptr;
	m_constructorFunction = nullptr;
	m_startFunction = nullptr;
	m_updateFunction = nullptr;
	m_scriptObject = nullptr;
	m_module = nullptr;
	m_scriptEngine = nullptr;
	m_isInstantiated = false;
}

ScriptInstance::~ScriptInstance()
{
	// For some weird reason, it only
	// get's released when called twice...
	m_scriptObject->Release();
	m_scriptObject->Release();

	m_gameObject = nullptr;
	m_constructorFunction = nullptr;
	m_startFunction = nullptr;
	m_updateFunction = nullptr;
	m_scriptEngine = nullptr;
	m_isInstantiated = false;
}

bool ScriptInstance::Instantiate(const string& path, GameObject* gameObject, ScriptEngine* scriptEngine)
{
	m_scriptEngine = scriptEngine;

	// Extract properties from path
	m_scriptPath = path;
	m_gameObject = gameObject;
	m_className = FileSystem::GetFileNameNoExtensionFromPath(m_scriptPath);
	m_moduleName = m_className + m_gameObject->GetID();
	m_constructorDeclaration = m_className + " @" + m_className + "(GameObject @)";

	// Instantiate the script
	m_isInstantiated = CreateScriptObject();

	return m_isInstantiated;
}

bool ScriptInstance::IsInstantiated()
{
	return m_isInstantiated;
}

string ScriptInstance::GetScriptPath()
{
	return m_scriptPath;
}

void ScriptInstance::ExecuteStart()
{
	m_scriptEngine->ExecuteCall(m_startFunction, m_scriptObject);
}

void ScriptInstance::ExecuteUpdate()
{
	m_scriptEngine->ExecuteCall(m_updateFunction, m_scriptObject);
}

bool ScriptInstance::CreateScriptObject()
{
	// Create module
	m_module = make_shared<Module>(m_moduleName, m_scriptEngine);
	bool result = m_module->LoadScript(m_scriptPath);
	if (!result)
		return false;

	// Get type
	auto type_id = m_module->GetAsIScriptModule()->GetTypeIdByDecl(m_className.c_str());
	asITypeInfo* type = m_scriptEngine->GetAsIScriptEngine()->GetTypeInfoById(type_id);
	if (!type)
		return false;

	// Get functions in the script
	m_startFunction = type->GetMethodByDecl("void Start()"); // Get the Start function from the script
	m_updateFunction = type->GetMethodByDecl("void Update()"); // Get the Update function from the script
	m_constructorFunction = type->GetFactoryByDecl(m_constructorDeclaration.c_str()); // Get the constructor function from the script
	if (!m_constructorFunction)
	{
		LOG_ERROR("Couldn't find the appropriate factory for the type '" + m_className + "'");
		return false;
	}

	asIScriptContext* context = m_scriptEngine->RequestContext(); // request a context
	int r = context->Prepare(m_constructorFunction); // prepare the context to call the factory function
	if (r < 0) return false;

	r = context->SetArgObject(0, m_gameObject); // Pass the gameobject as the constructor's parameter
	if (r < 0) return false;

	r = context->Execute(); // execute the call
	if (r < 0) return false;

	// get the object that was created
	m_scriptObject = *static_cast<asIScriptObject**>(context->GetAddressOfReturnValue());

	// if you're going to store the object you must increase the reference,
	// otherwise it will be destroyed when the context is reused or destroyed.
	m_scriptObject->AddRef();

	// return context
	m_scriptEngine->ReturnContext(context);

	return true;
}
<|endoftext|>


<commit_before>// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: echo 'extern int a; template<typename T> int a2 = T::error;' > %t/a.h
// RUN: echo 'extern int b;' > %t/b.h
// RUN: echo 'extern int c = 0;' > %t/c.h
// RUN: echo 'module a { header "a.h" header "b.h" header "c.h" }' > %t/modulemap
// RUN: echo 'module other {}' > %t/other.modulemap

// We lazily check that the files referenced by an explicitly-specified .pcm
// file exist. Test this by removing files and ensuring that the compilation
// still succeeds.
//
// RUN: %clang_cc1 -fmodules -I %t -emit-module -fmodule-name=a -x c++ %t/modulemap -o %t/a.pcm \
// RUN:            -fmodule-map-file=%t/other.modulemap \
// RUN:            -fmodules-embed-file=%t/modulemap -fmodules-embed-file=%t/other.modulemap
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s
// RUN: rm %t/modulemap
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s
// RUN: rm %t/other.modulemap
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s
// RUN: rm %t/b.h
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s --check-prefix=MISSING-B
// RUN: rm %t/a.h
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -verify

#include "a.h" // expected-error {{file not found}}
int x = b;

#ifdef ERRORS
int y = a2<int>;
// CHECK: In module 'a':
// CHECK-NEXT: a.h:1:45: error:

// MISSING-B: could not find file '{{.*}}b.h'
// MISSING-B-NOT: please delete the module cache
#endif

// RUN: not %clang_cc1 -fmodules -I %t -emit-module -fmodule-name=a -x c++ /dev/null -o %t/a.pcm \
// RUN:                -fmodules-embed-file=%t/does-not-exist 2>&1 | FileCheck %s --check-prefix=MISSING-EMBED
// MISSING-EMBED: fatal error: file '{{.*}}does-not-exist' specified by '-fmodules-embed-file=' not found
<commit_msg>Don't run explicit-modules-missing-files.cpp on Windows<commit_after>// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: echo 'extern int a; template<typename T> int a2 = T::error;' > %t/a.h
// RUN: echo 'extern int b;' > %t/b.h
// RUN: echo 'extern int c = 0;' > %t/c.h
// RUN: echo 'module a { header "a.h" header "b.h" header "c.h" }' > %t/modulemap
// RUN: echo 'module other {}' > %t/other.modulemap

// We lazily check that the files referenced by an explicitly-specified .pcm
// file exist. Test this by removing files and ensuring that the compilation
// still succeeds.
//
// RUN: %clang_cc1 -fmodules -I %t -emit-module -fmodule-name=a -x c++ %t/modulemap -o %t/a.pcm \
// RUN:            -fmodule-map-file=%t/other.modulemap \
// RUN:            -fmodules-embed-file=%t/modulemap -fmodules-embed-file=%t/other.modulemap
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s
// RUN: rm %t/modulemap
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s
// RUN: rm %t/other.modulemap
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s
// RUN: rm %t/b.h
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
// RUN: not %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -DERRORS 2>&1 | FileCheck %s --check-prefix=MISSING-B
// RUN: rm %t/a.h
// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -verify

// Oftentimes on Windows there are open handles, and deletion will fail.
// REQUIRES: can-remove-opened-file

#include "a.h" // expected-error {{file not found}}
int x = b;

#ifdef ERRORS
int y = a2<int>;
// CHECK: In module 'a':
// CHECK-NEXT: a.h:1:45: error:

// MISSING-B: could not find file '{{.*}}b.h'
// MISSING-B-NOT: please delete the module cache
#endif

// RUN: not %clang_cc1 -fmodules -I %t -emit-module -fmodule-name=a -x c++ /dev/null -o %t/a.pcm \
// RUN:                -fmodules-embed-file=%t/does-not-exist 2>&1 | FileCheck %s --check-prefix=MISSING-EMBED
// MISSING-EMBED: fatal error: file '{{.*}}does-not-exist' specified by '-fmodules-embed-file=' not found
<|endoftext|>


<commit_before>/** @file
 *
 * @ingroup spatdiflib
 *
 * @brief
 *
 * @details
 *
 * @authors Chikashi Miyama, Trond Lossius
 *
 * @copyright Copyright (C) 2013 - 2014 Zurich University of the Arts, Institute for Computer Music and Sound Technology @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include <vector>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <unordered_set>
#include "sdMain.h"
#include "tinyxml2.h"
#include "JSONNode.h"
#include "sdSaver.h"

using namespace tinyxml2;

XMLDeclaration* sdXMLSaver::XMLDeclarationSection(XMLDocument &xml){
    XMLDeclaration* decl = xml.NewDeclaration();
    decl->SetValue("xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"");
    return decl;
}

XMLElement* sdXMLSaver::XMLOrderingSection(XMLDocument &xml, const sdScene &scene){
    XMLElement* ordering = xml.NewElement("ordering");
    XMLText* orderingText = xml.NewText(scene.getOrderingAsString().c_str());
    ordering->InsertEndChild(orderingText);
    return  ordering;
}

XMLElement* sdXMLSaver::XMLMetaSection(XMLDocument &xml, const sdScene &scene){

    XMLElement* metaSection = xml.NewElement("meta");

    // add info section to meta
    std::vector<EExtension> extensions = sdSpec::getDataSetEnabledExtensions();
    for(auto &extension : extensions){
        std::unordered_set<std::string> identifiers = scene.getIdentifiers(extension);
        if(identifiers.empty()) continue;
        for(auto &identifier : identifiers){
            std::shared_ptr<sdProtoDataSet> protoDataSet = scene.getProtoDataSet(extension, identifier);
            std::unordered_set<EDescriptor> keys = protoDataSet->getKeys();
            XMLElement * extensionElement = xml.NewElement(sdSpec::extensionToString(extension).c_str());

            for(auto &key : keys){
                std::string descriptorString = sdSpec::descriptorToString(key);
                std::string value = protoDataSet->getValueAsString(key);
                XMLElement * datasetElement = xml.NewElement(descriptorString.c_str());
                if(!datasetElement) continue;
                XMLText * text = xml.NewText(value.c_str());
                if(!text) continue;

                datasetElement->InsertEndChild(text);
                extensionElement->InsertEndChild(datasetElement);
            }
            metaSection->InsertEndChild(extensionElement);
        }
    }

    // add extensions to meta
    size_t num = scene.getNumberOfActivatedExtensions();
    if(num > 0){
        XMLElement* extensions = xml.NewElement("extensions");
        std::string extString;
        auto extensionNames = scene.getActivatedExtensionsAsStrings();
        std::for_each(extensionNames.begin(), extensionNames.end(),[&extString](std::string ext){
            EExtension extension = sdSpec::stringToExtension(ext);
            if(!sdSpec::isCoreSpec(extension)){
                extString = ext;
                extString += " ";
            }
        });
        extString.erase(extString.size()-1, extString.size()-1);
        XMLText* extensionsText = xml.NewText(extString.c_str());
        extensions->InsertEndChild(extensionsText);
        metaSection->InsertEndChild(extensions);
    }

    // add other meta infomation such as constant position or sound file definition
    auto allMetas = scene.getAllMetas();

    std::for_each(allMetas.begin(), allMetas.end(), [&](std::pair<sdProtoEntity*, std::shared_ptr<sdProtoMeta>> metaPair ) {
        auto entity = metaPair.first;
        auto meta = metaPair.second;
        std::string previousName;
        std::string previousExtension;
        sdProtoEntity * previousEntity = nullptr;
        XMLElement* kind;
        XMLElement* extension;

        //event
        //kind = xml.NewElement(entity->getKindAsString().c_str());
        kind = xml.NewElement(std::string("source").c_str());

        // the name of entity always comes first
        XMLElement* name = xml.NewElement("name"); // entity name
        auto entityName = scene.getEntityName(entity);
        XMLText* nameText = xml.NewText(entityName.c_str());
        name->InsertEndChild(nameText);
        kind->InsertEndChild(name);

        // packaging - combining element and text (value)
        XMLElement* element = xml.NewElement(meta->getDescriptorAsString().c_str());
        XMLText* text = xml.NewText(meta->getValueAsString().c_str());
        element->InsertEndChild(text);

        std::string relevantExtension = sdSpec::extensionToString(sdSpec::getExtensionOfDescriptor(meta->getDescriptor()));

        if(relevantExtension == "core"){
            kind->InsertEndChild(element);
            metaSection->InsertEndChild(kind);
        }else{

            if( (entity != previousEntity ) || (previousExtension != relevantExtension)){
                // if different entity, time, or extension from the previous put extension tag
                extension = xml.NewElement((relevantExtension).c_str());
            }
            extension->InsertEndChild(element);
            kind->InsertEndChild(extension);
            metaSection->InsertEndChild(kind);
        }

        previousEntity = entity; // store current name in order to avoid the dupplication.
        previousExtension = relevantExtension;
    });

    // add ordering
    metaSection->InsertEndChild(XMLOrderingSection(xml, scene));

    return metaSection;
}

std::string sdXMLSaver::toString(const sdScene &scene){

    XMLDocument xml;
    xml.InsertEndChild(XMLDeclarationSection(xml));

    XMLElement* spatdif = xml.NewElement("spatdif");
    spatdif->SetAttribute("version", "0.4");
    xml.InsertEndChild(spatdif);

    spatdif->InsertEndChild(sdXMLSaver::XMLMetaSection(xml, scene));

    std::unordered_map<std::string, sdEntity> entities = scene.getEntities();

    // TIME Section
    /* ordered by time */
    if(scene.getOrdering() == EOrdering::SD_TIME){
        auto eventTime = scene.getNextEventTime(-1.0);
        while(eventTime.second){

            // add <time>
            XMLElement* timeElement = xml.NewElement("time");
            timeElement->InsertEndChild(xml.NewText(std::to_string(eventTime.first).c_str()));
            spatdif->InsertEndChild(timeElement);

            for(auto entity : entities){
                auto entityEventsAtTime = entity.second.getEvents(eventTime.first);
                if(entityEventsAtTime.empty()) continue;

                XMLElement * kindElement = xml.NewElement(entity.second.getKindAsString().c_str());
                XMLElement * nameElement = xml.NewElement("name"); // entity name

                XMLText* nameText = xml.NewText(entity.first.c_str());
                nameElement->InsertEndChild(nameText);
                kindElement->InsertEndChild(nameElement);

                XMLElement* extensionElement = nullptr;
                std::string previousExtension = "";
                for(auto entityEvent : entityEventsAtTime){
                    XMLElement* eventElement = xml.NewElement(entityEvent->getDescriptorAsString().c_str());
                    eventElement->InsertEndChild(xml.NewText(entityEvent->getValueAsString().c_str()));
                    std::string relevantExtension = sdSpec::extensionToString(sdSpec::getExtensionOfDescriptor(entityEvent->getDescriptor()));

                    if(relevantExtension == "core"){
                        kindElement->InsertEndChild(eventElement);
                    }else{// extension
                        if(previousExtension == relevantExtension){
                            extensionElement->InsertEndChild(eventElement);
                        }else{
                            extensionElement = xml.NewElement((relevantExtension).c_str());
                            extensionElement->InsertEndChild(eventElement);
                            kindElement->InsertEndChild(extensionElement);
                        }
                    }
                    previousExtension = relevantExtension;
                }
                spatdif->InsertEndChild(kindElement);
            }
            eventTime = scene.getNextEventTime(eventTime.first);
        }

    }else if(scene.getOrdering() == EOrdering::SD_TRACK){
        // 1. Sort vector by name alphabetically

        for(auto it = entities.begin(); it != entities.end(); it++ ){
            auto namedEntity = *it;
            auto entityName = (*it).first;
            auto entity = (*it).second;
            auto events = entity.getEvents();

            for(auto iit = events.begin(); iit != events.end(); iit++){
                std::shared_ptr<sdProtoEvent> event = *iit;
                XMLElement* time = xml.NewElement("time");
                XMLText* timeText = xml.NewText(event->getTimeAsString().c_str());
                time->InsertEndChild(timeText);
                spatdif->InsertEndChild(time);

                XMLElement* kind;
                kind = xml.NewElement(entity.getKindAsString().c_str());
                XMLElement* name = xml.NewElement("name");
                XMLText* nameText = xml.NewText(entityName.c_str());
                name->InsertEndChild(nameText);
                kind->InsertEndChild(name);

                XMLElement* element = xml.NewElement(event->getDescriptorAsString().c_str());
                XMLText* text = xml.NewText(event->getValueAsString().c_str());
                element->InsertEndChild(text);
                kind->InsertEndChild(element);

                spatdif->InsertEndChild(kind);
            }
        }
    }

    XMLPrinter printer;
    xml.Print(&printer);
    return std::string(printer.CStr());

}

std::string sdJSONSaver::toString(const sdScene &sdScene){
    return "";
}

std::string sdYAMLSaver::toString(const sdScene &sdScene){
    return "";
}
<commit_msg>[bug] extension before all meta definitions<commit_after>/** @file
 *
 * @ingroup spatdiflib
 *
 * @brief
 *
 * @details
 *
 * @authors Chikashi Miyama, Trond Lossius
 *
 * @copyright Copyright (C) 2013 - 2014 Zurich University of the Arts, Institute for Computer Music and Sound Technology @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include <vector>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <unordered_set>
#include "sdMain.h"
#include "tinyxml2.h"
#include "JSONNode.h"
#include "sdSaver.h"

using namespace tinyxml2;

XMLDeclaration* sdXMLSaver::XMLDeclarationSection(XMLDocument &xml){
    XMLDeclaration* decl = xml.NewDeclaration();
    decl->SetValue("xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"");
    return decl;
}

XMLElement* sdXMLSaver::XMLOrderingSection(XMLDocument &xml, const sdScene &scene){
    XMLElement* ordering = xml.NewElement("ordering");
    XMLText* orderingText = xml.NewText(scene.getOrderingAsString().c_str());
    ordering->InsertEndChild(orderingText);
    return  ordering;
}

XMLElement* sdXMLSaver::XMLMetaSection(XMLDocument &xml, const sdScene &scene){

    XMLElement* metaSection = xml.NewElement("meta");

    // add extensions to meta
    size_t num = scene.getNumberOfActivatedExtensions();
    if(num > 0){
        XMLElement* extensions = xml.NewElement("extensions");
        std::string extString;
        auto extensionNames = scene.getActivatedExtensionsAsStrings();
        std::for_each(extensionNames.begin(), extensionNames.end(),[&extString](std::string ext){
            EExtension extension = sdSpec::stringToExtension(ext);
            if(!sdSpec::isCoreSpec(extension)){
                extString = ext;
                extString += " ";
            }
        });
        extString.erase(extString.size()-1, extString.size()-1);
        XMLText* extensionsText = xml.NewText(extString.c_str());
        extensions->InsertEndChild(extensionsText);
        metaSection->InsertEndChild(extensions);
    }

    // add info section to meta
    std::vector<EExtension> extensions = sdSpec::getDataSetEnabledExtensions();
    for(auto &extension : extensions){
        std::unordered_set<std::string> identifiers = scene.getIdentifiers(extension);
        if(identifiers.empty()) continue;
        for(auto &identifier : identifiers){
            std::shared_ptr<sdProtoDataSet> protoDataSet = scene.getProtoDataSet(extension, identifier);
            std::unordered_set<EDescriptor> keys = protoDataSet->getKeys();
            XMLElement * extensionElement = xml.NewElement(sdSpec::extensionToString(extension).c_str());

            for(auto &key : keys){
                std::string descriptorString = sdSpec::descriptorToString(key);
                std::string value = protoDataSet->getValueAsString(key);
                XMLElement * datasetElement = xml.NewElement(descriptorString.c_str());
                if(!datasetElement) continue;
                XMLText * text = xml.NewText(value.c_str());
                if(!text) continue;

                datasetElement->InsertEndChild(text);
                extensionElement->InsertEndChild(datasetElement);
            }
            metaSection->InsertEndChild(extensionElement);
        }
    }

    // add other meta infomation such as constant position or sound file definition
    auto allMetas = scene.getAllMetas();

    std::for_each(allMetas.begin(), allMetas.end(), [&](std::pair<sdProtoEntity*, std::shared_ptr<sdProtoMeta>> metaPair ) {
        auto entity = metaPair.first;
        auto meta = metaPair.second;
        std::string previousName;
        std::string previousExtension;
        sdProtoEntity * previousEntity = nullptr;
        XMLElement* kind;
        XMLElement* extension;

        //event
        //kind = xml.NewElement(entity->getKindAsString().c_str());
        kind = xml.NewElement(std::string("source").c_str());

        // the name of entity always comes first
        XMLElement* name = xml.NewElement("name"); // entity name
        auto entityName = scene.getEntityName(entity);
        XMLText* nameText = xml.NewText(entityName.c_str());
        name->InsertEndChild(nameText);
        kind->InsertEndChild(name);

        // packaging - combining element and text (value)
        XMLElement* element = xml.NewElement(meta->getDescriptorAsString().c_str());
        XMLText* text = xml.NewText(meta->getValueAsString().c_str());
        element->InsertEndChild(text);

        std::string relevantExtension = sdSpec::extensionToString(sdSpec::getExtensionOfDescriptor(meta->getDescriptor()));

        if(relevantExtension == "core"){
            kind->InsertEndChild(element);
            metaSection->InsertEndChild(kind);
        }else{

            if( (entity != previousEntity ) || (previousExtension != relevantExtension)){
                // if different entity, time, or extension from the previous put extension tag
                extension = xml.NewElement((relevantExtension).c_str());
            }
            extension->InsertEndChild(element);
            kind->InsertEndChild(extension);
            metaSection->InsertEndChild(kind);
        }

        previousEntity = entity; // store current name in order to avoid the dupplication.
        previousExtension = relevantExtension;
    });

    // add ordering
    metaSection->InsertEndChild(XMLOrderingSection(xml, scene));

    return metaSection;
}

std::string sdXMLSaver::toString(const sdScene &scene){

    XMLDocument xml;
    xml.InsertEndChild(XMLDeclarationSection(xml));

    XMLElement* spatdif = xml.NewElement("spatdif");
    spatdif->SetAttribute("version", "0.4");
    xml.InsertEndChild(spatdif);

    spatdif->InsertEndChild(sdXMLSaver::XMLMetaSection(xml, scene));

    std::unordered_map<std::string, sdEntity> entities = scene.getEntities();

    // TIME Section
    /* ordered by time */
    if(scene.getOrdering() == EOrdering::SD_TIME){
        auto eventTime = scene.getNextEventTime(-1.0);
        while(eventTime.second){

            // add <time>
            XMLElement* timeElement = xml.NewElement("time");
            timeElement->InsertEndChild(xml.NewText(std::to_string(eventTime.first).c_str()));
            spatdif->InsertEndChild(timeElement);

            for(auto entity : entities){
                auto entityEventsAtTime = entity.second.getEvents(eventTime.first);
                if(entityEventsAtTime.empty()) continue;

                XMLElement * kindElement = xml.NewElement(entity.second.getKindAsString().c_str());
                XMLElement * nameElement = xml.NewElement("name"); // entity name

                XMLText* nameText = xml.NewText(entity.first.c_str());
                nameElement->InsertEndChild(nameText);
                kindElement->InsertEndChild(nameElement);

                XMLElement* extensionElement = nullptr;
                std::string previousExtension = "";
                for(auto entityEvent : entityEventsAtTime){
                    XMLElement* eventElement = xml.NewElement(entityEvent->getDescriptorAsString().c_str());
                    eventElement->InsertEndChild(xml.NewText(entityEvent->getValueAsString().c_str()));
                    std::string relevantExtension = sdSpec::extensionToString(sdSpec::getExtensionOfDescriptor(entityEvent->getDescriptor()));

                    if(relevantExtension == "core"){
                        kindElement->InsertEndChild(eventElement);
                    }else{// extension
                        if(previousExtension == relevantExtension){
                            extensionElement->InsertEndChild(eventElement);
                        }else{
                            extensionElement = xml.NewElement((relevantExtension).c_str());
                            extensionElement->InsertEndChild(eventElement);
                            kindElement->InsertEndChild(extensionElement);
                        }
                    }
                    previousExtension = relevantExtension;
                }
                spatdif->InsertEndChild(kindElement);
            }
            eventTime = scene.getNextEventTime(eventTime.first);
        }

    }else if(scene.getOrdering() == EOrdering::SD_TRACK){
        // 1. Sort vector by name alphabetically

        for(auto it = entities.begin(); it != entities.end(); it++ ){
            auto namedEntity = *it;
            auto entityName = (*it).first;
            auto entity = (*it).second;
            auto events = entity.getEvents();

            for(auto iit = events.begin(); iit != events.end(); iit++){
                std::shared_ptr<sdProtoEvent> event = *iit;
                XMLElement* time = xml.NewElement("time");
                XMLText* timeText = xml.NewText(event->getTimeAsString().c_str());
                time->InsertEndChild(timeText);
                spatdif->InsertEndChild(time);

                XMLElement* kind;
                kind = xml.NewElement(entity.getKindAsString().c_str());
                XMLElement* name = xml.NewElement("name");
                XMLText* nameText = xml.NewText(entityName.c_str());
                name->InsertEndChild(nameText);
                kind->InsertEndChild(name);

                XMLElement* element = xml.NewElement(event->getDescriptorAsString().c_str());
                XMLText* text = xml.NewText(event->getValueAsString().c_str());
                element->InsertEndChild(text);
                kind->InsertEndChild(element);

                spatdif->InsertEndChild(kind);
            }
        }
    }

    XMLPrinter printer;
    xml.Print(&printer);
    return std::string(printer.CStr());

}

std::string sdJSONSaver::toString(const sdScene &sdScene){
    return "";
}

std::string sdYAMLSaver::toString(const sdScene &sdScene){
    return "";
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2014 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "VCommentBrowser.h"
#include "VisualizationBase/src/items/ItemStyle.h"
#include "VisualizationBase/src/shapes/Shape.h"
#include "VisualizationBase/src/VisualizationManager.h"

namespace Comments {

ITEM_COMMON_DEFINITIONS(VCommentBrowser, "item")

const QSize VCommentBrowser::defaultSize = QSize(400, 300);

VCommentBrowser::VCommentBrowser(Visualization::Item* parent, const QUrl& url, const StyleType* style)
	: VCommentBrowser{parent, url, defaultSize, style}
{}

VCommentBrowser::VCommentBrowser(Visualization::Item* parent, const QUrl& url, QSize size, const StyleType* style)
	: Super(parent, style), browser_{new QGraphicsWebView(this)}, size_{size}
{
	browser_->setUrl(url);
}

VCommentBrowser::VCommentBrowser(Visualization::Item* parent, const QString& content, const StyleType* style)
	: Super(parent, style), browser_{new QGraphicsWebView(this)}, size_{defaultSize}
{
	browser_->setResizesToContents(true);
	browser_->setHtml(content);
	browser_->setMaximumSize(defaultSize);
	browser_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}

VCommentBrowser::~VCommentBrowser()
{
	//TODO: Remove this dirty hack. This looks like a bug in QGraphicsWebView, but more investigation is needed.
	// This item is originally removed from the scene when SAFE_DELETE_ITEM is called. It should not be necessary to
	// add this item to the scene before destroying the browser_. However, the destructor of browser seems to
	// eventually call QGraphicsScene::removeItem(). But where does it get a scene from?! If we don't add 'this' to
	// the scene browser_->scene() returns nullptr. This resutls in a Segmentation Fault.
	// More debugging is required, preferrably with symbols for the source code that happens when the destructor of
	// QGraphicsWebView is called.
	Visualization::VisualizationManager::instance().mainScene()->addItem(this);
	SAFE_DELETE(browser_);
}

void VCommentBrowser::determineChildren() {}

void VCommentBrowser::updateGeometry(int, int)
{
	browser_->setMaximumSize(size_);

	if (hasShape())
	{
		getShape()->setInnerSize(size_.width(), size_.height());
		browser_->setPos(getShape()->contentLeft(), getShape()->contentTop());
	}
	else
	{
		setSize(size_);
		browser_->setPos(0, 0);
	}
}

QList<Visualization::Item*> VCommentBrowser::childItems() const
{
	return {};
}

void VCommentBrowser::updateSize(QSize size)
{
	if (size.width() > 0 && size.height() > 0)
		size_ = size;
}

}
<commit_msg>Make Browser comments resize properly<commit_after>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2014 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "VCommentBrowser.h"
#include "VisualizationBase/src/items/ItemStyle.h"
#include "VisualizationBase/src/shapes/Shape.h"
#include "VisualizationBase/src/VisualizationManager.h"

namespace Comments {

ITEM_COMMON_DEFINITIONS(VCommentBrowser, "item")

const QSize VCommentBrowser::defaultSize = QSize(400, 300);

VCommentBrowser::VCommentBrowser(Visualization::Item* parent, const QUrl& url, const StyleType* style)
	: VCommentBrowser{parent, url, defaultSize, style}
{}

VCommentBrowser::VCommentBrowser(Visualization::Item* parent, const QUrl& url, QSize size, const StyleType* style)
	: Super(parent, style), browser_{new QGraphicsWebView(this)}, size_{size}
{
	browser_->setUrl(url);
}

VCommentBrowser::VCommentBrowser(Visualization::Item* parent, const QString& content, const StyleType* style)
	: Super(parent, style), browser_{new QGraphicsWebView(this)}, size_{defaultSize}
{
	browser_->setResizesToContents(true);
	browser_->setHtml(content);
	browser_->resize(size_);
}

VCommentBrowser::~VCommentBrowser()
{
	//TODO: Remove this dirty hack. This looks like a bug in QGraphicsWebView, but more investigation is needed.
	// This item is originally removed from the scene when SAFE_DELETE_ITEM is called. It should not be necessary to
	// add this item to the scene before destroying the browser_. However, the destructor of browser seems to
	// eventually call QGraphicsScene::removeItem(). But where does it get a scene from?! If we don't add 'this' to
	// the scene browser_->scene() returns nullptr. This resutls in a Segmentation Fault.
	// More debugging is required, preferrably with symbols for the source code that happens when the destructor of
	// QGraphicsWebView is called.
	Visualization::VisualizationManager::instance().mainScene()->addItem(this);
	SAFE_DELETE(browser_);
}

void VCommentBrowser::determineChildren()
{
	if (size_.isValid())
		browser_->resize(size_);
}

void VCommentBrowser::updateGeometry(int, int)
{
	if (hasShape())
	{
		getShape()->setInnerSize(size_.width(), size_.height());
		browser_->setPos(getShape()->contentLeft(), getShape()->contentTop());
	}
	else
	{
		setSize(size_);
		browser_->setPos(0, 0);
	}
}

QList<Visualization::Item*> VCommentBrowser::childItems() const
{
	return {};
}

void VCommentBrowser::updateSize(QSize size)
{
	if (size.width() > 0 && size.height() > 0)
		size_ = size;
	setUpdateNeeded(StandardUpdate);
}

}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2019, Ford Motor Company, Livio
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following
 disclaimer in the documentation and/or other materials provided with the
 distribution.

 Neither the name of the the copyright holders nor the names of their
 contributors may be used to endorse or promote products derived from this
 software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "app_service_rpc_plugin/commands/mobile/publish_app_service_request.h"
#include "application_manager/application_impl.h"
#include "application_manager/message_helper.h"
#include "application_manager/rpc_service.h"
#include "interfaces/MOBILE_API.h"
#include "sdl_rpc_plugin/extensions/system_capability_app_extension.h"

namespace app_service_rpc_plugin {
using namespace application_manager;
namespace commands {

PublishAppServiceRequest::PublishAppServiceRequest(
    const application_manager::commands::MessageSharedPtr& message,
    ApplicationManager& application_manager,
    app_mngr::rpc_service::RPCService& rpc_service,
    app_mngr::HMICapabilities& hmi_capabilities,
    policy::PolicyHandlerInterface& policy_handler)
    : CommandRequestImpl(message,
                         application_manager,
                         rpc_service,
                         hmi_capabilities,
                         policy_handler)
    , plugin_(NULL) {
  auto plugin = application_manager.GetPluginManager().FindPluginToProcess(
      mobile_apis::FunctionID::PublishAppServiceID,
      app_mngr::commands::Command::CommandSource::SOURCE_MOBILE);
  if (plugin) {
    plugin_ = dynamic_cast<AppServiceRpcPlugin*>(&(*plugin));
  }
}

PublishAppServiceRequest::~PublishAppServiceRequest() {}

bool PublishAppServiceRequest::ValidateManifest(
    smart_objects::SmartObject& manifest) {
  if (manifest.keyExists(strings::uri_scheme)) {
    Json::Value value;
    Json::Reader reader;
    if (!reader.parse(manifest[strings::uri_scheme].asString(), value)) {
      SendResponse(false,
                   mobile_apis::Result::INVALID_DATA,
                   "Provided uriScheme was not valid JSON");
      return false;
    }
  }
  return true;
}

void PublishAppServiceRequest::Run() {
  LOG4CXX_AUTO_TRACE(logger_);
  LOG4CXX_DEBUG(logger_, "Received a PublishAppService " << connection_key());
  MessageHelper::PrintSmartObject(*message_);

  smart_objects::SmartObject response_params =
      smart_objects::SmartObject(smart_objects::SmartType_Map);
  smart_objects::SmartObject manifest =
      (*message_)[strings::msg_params][strings::app_service_manifest];
  if (!ValidateManifest(manifest)) {
    return;
  }

  ApplicationSharedPtr app = application_manager_.application(connection_key());
  auto& ext =
      sdl_rpc_plugin::SystemCapabilityAppExtension::ExtractExtension(*app);
  ext.SubscribeTo(mobile_apis::SystemCapabilityType::APP_SERVICES);

  smart_objects::SmartObject service_record =
      application_manager_.GetAppServiceManager().PublishAppService(
          manifest, true, connection_key());

  std::string requested_service_name = "";

  if ((*message_)[strings::msg_params][strings::app_service_manifest].keyExists(
          strings::service_name)) {
    requested_service_name =
        (*message_)[strings::msg_params][strings::app_service_manifest]
                   [strings::service_name].asString();
  }

  std::string requested_service_type =
      (*message_)[strings::msg_params][strings::app_service_manifest]
                 [strings::service_type].asString();

  smart_objects::SmartArray* requested_handled_rpcs = NULL;
  if ((*message_)[strings::msg_params][strings::app_service_manifest].keyExists(
          strings::handled_rpcs)) {
    requested_handled_rpcs =
        (*message_)[strings::msg_params][strings::app_service_manifest]
                   [strings::handled_rpcs].asArray();
  }

  bool result =
      policy_handler_.CheckAppServiceParameters(app->policy_app_id(),
                                                requested_service_name,
                                                requested_service_type,
                                                requested_handled_rpcs);

  if (!result) {
    SendResponse(false,
                 mobile_apis::Result::DISALLOWED,
                 "Service disallowed by policies",
                 NULL);
  }

  response_params[strings::app_service_record] = service_record;

  SendResponse(true, mobile_apis::Result::SUCCESS, NULL, &response_params);
}

}  // namespace commands
}  // namespace app_service_rpc_plugin
<commit_msg>Move publish app service & subscribe after policy check<commit_after>/*
 Copyright (c) 2019, Ford Motor Company, Livio
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following
 disclaimer in the documentation and/or other materials provided with the
 distribution.

 Neither the name of the the copyright holders nor the names of their
 contributors may be used to endorse or promote products derived from this
 software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "app_service_rpc_plugin/commands/mobile/publish_app_service_request.h"
#include "application_manager/application_impl.h"
#include "application_manager/message_helper.h"
#include "application_manager/rpc_service.h"
#include "interfaces/MOBILE_API.h"
#include "sdl_rpc_plugin/extensions/system_capability_app_extension.h"

namespace app_service_rpc_plugin {
using namespace application_manager;
namespace commands {

PublishAppServiceRequest::PublishAppServiceRequest(
    const application_manager::commands::MessageSharedPtr& message,
    ApplicationManager& application_manager,
    app_mngr::rpc_service::RPCService& rpc_service,
    app_mngr::HMICapabilities& hmi_capabilities,
    policy::PolicyHandlerInterface& policy_handler)
    : CommandRequestImpl(message,
                         application_manager,
                         rpc_service,
                         hmi_capabilities,
                         policy_handler)
    , plugin_(NULL) {
  auto plugin = application_manager.GetPluginManager().FindPluginToProcess(
      mobile_apis::FunctionID::PublishAppServiceID,
      app_mngr::commands::Command::CommandSource::SOURCE_MOBILE);
  if (plugin) {
    plugin_ = dynamic_cast<AppServiceRpcPlugin*>(&(*plugin));
  }
}

PublishAppServiceRequest::~PublishAppServiceRequest() {}

bool PublishAppServiceRequest::ValidateManifest(
    smart_objects::SmartObject& manifest) {
  if (manifest.keyExists(strings::uri_scheme)) {
    Json::Value value;
    Json::Reader reader;
    if (!reader.parse(manifest[strings::uri_scheme].asString(), value)) {
      SendResponse(false,
                   mobile_apis::Result::INVALID_DATA,
                   "Provided uriScheme was not valid JSON");
      return false;
    }
  }
  return true;
}

void PublishAppServiceRequest::Run() {
  LOG4CXX_AUTO_TRACE(logger_);
  LOG4CXX_DEBUG(logger_, "Received a PublishAppService " << connection_key());
  MessageHelper::PrintSmartObject(*message_);

  smart_objects::SmartObject response_params =
      smart_objects::SmartObject(smart_objects::SmartType_Map);
  smart_objects::SmartObject manifest =
      (*message_)[strings::msg_params][strings::app_service_manifest];
  if (!ValidateManifest(manifest)) {
    return;
  }

  ApplicationSharedPtr app = application_manager_.application(connection_key());

  std::string requested_service_name = "";

  if ((*message_)[strings::msg_params][strings::app_service_manifest].keyExists(
          strings::service_name)) {
    requested_service_name =
        (*message_)[strings::msg_params][strings::app_service_manifest]
                   [strings::service_name].asString();
  }

  std::string requested_service_type =
      (*message_)[strings::msg_params][strings::app_service_manifest]
                 [strings::service_type].asString();

  smart_objects::SmartArray* requested_handled_rpcs = NULL;
  if ((*message_)[strings::msg_params][strings::app_service_manifest].keyExists(
          strings::handled_rpcs)) {
    requested_handled_rpcs =
        (*message_)[strings::msg_params][strings::app_service_manifest]
                   [strings::handled_rpcs].asArray();
  }

  bool result =
      policy_handler_.CheckAppServiceParameters(app->policy_app_id(),
                                                requested_service_name,
                                                requested_service_type,
                                                requested_handled_rpcs);

  if (!result) {
    SendResponse(false,
                 mobile_apis::Result::DISALLOWED,
                 "Service disallowed by policies",
                 NULL);
  }

  auto& ext =
      sdl_rpc_plugin::SystemCapabilityAppExtension::ExtractExtension(*app);
  ext.SubscribeTo(mobile_apis::SystemCapabilityType::APP_SERVICES);

  smart_objects::SmartObject service_record =
      application_manager_.GetAppServiceManager().PublishAppService(
          manifest, true, connection_key());

  response_params[strings::app_service_record] = service_record;

  SendResponse(true, mobile_apis::Result::SUCCESS, NULL, &response_params);
}

}  // namespace commands
}  // namespace app_service_rpc_plugin
<|endoftext|>