module procedures_complete_coordinates_writer_factory

use json_module, only: json_file
use procedures_checks, only: check_data_found
use types_string_wrapper, only: String_Wrapper
use classes_periodic_box, only: Abstract_Periodic_Box
use types_component_wrapper, only: Component_Wrapper
use procedures_mixture_inquirers, only:  component_has_positions, component_has_orientations
use types_component_coordinates_writer_selector, only: Component_Coordinates_Writer_Selector
use classes_component_coordinates_writer, only: Component_Coordinates_Writer_Wrapper
use procedures_component_coordinates_writer_factory, only: component_coordinates_writer_create => &
    create, component_coordinates_writer_destroy => destroy
use classes_complete_coordinates_writer, only: Abstract_Complete_Coordinates_Writer, &
    Concrete_Complete_Coordinates_Writer, Null_Complete_Coordinates_Writer
use procedures_writers_inquirers, only: property_write_coordinates => write_coordinates

implicit none

private
public :: create, destroy

contains

    subroutine create(coordinates, paths, basename, periodic_boxes, components, generating_data, &
        prefix)
        class(Abstract_Complete_Coordinates_Writer), allocatable, intent(out) :: coordinates
        type(String_Wrapper), intent(in) :: paths(:)
        character(len=*), intent(in) :: basename
        class(Abstract_Periodic_Box), intent(in) :: periodic_boxes(:)
        type(Component_Wrapper), intent(in) :: components(:, :)
        type(json_file), intent(inout) :: generating_data
        character(len=*), intent(in) :: prefix

        integer :: period
        logical :: write_coordinates
        character(len=:), allocatable :: data_field
        logical :: data_found

        type(Component_Coordinates_Writer_Wrapper) :: components_coordinates(size(components, 1), &
            size(components, 2))
        type(Component_Coordinates_Writer_Selector) :: coordinates_selector

        write_coordinates = property_write_coordinates(generating_data, prefix)
        if (write_coordinates) then
            data_field = prefix//"Coordinates.period"
            call generating_data%get(data_field, period, data_found)
            call check_data_found(data_field, data_found)
            allocate(Concrete_Complete_Coordinates_Writer :: coordinates)
        else
            period = 0
            allocate(Null_Complete_Coordinates_Writer :: coordinates)
        end if

        call set_selector(coordinates_selector, components)
        call component_coordinates_writer_create(components_coordinates, components, &
            write_coordinates)
        call coordinates%construct(paths, basename, periodic_boxes, components_coordinates, &
            coordinates_selector, period)
        call component_coordinates_writer_destroy(components_coordinates)
    end subroutine create

    subroutine set_selector(coordinates_selector, components)
        type(Component_Coordinates_Writer_Selector) :: coordinates_selector
        type(Component_Wrapper), intent(in) :: components(:, :)

        logical, dimension(size(components, 1), size(components, 2)) :: have_positions, &
            have_orientations
        integer :: i_box, i_component

        do i_box = 1, size(components, 2)
            do i_component = 1, size(components, 1)
                have_positions(i_component, i_box) = &
                    component_has_positions(components(i_component, i_box)%positions)
                have_orientations(i_component, i_box) = &
                    component_has_orientations(components(i_component, i_box)%orientations)
            end do
        end do
        coordinates_selector%write_positions = any(have_positions)
        coordinates_selector%write_orientations = any(have_orientations)
    end subroutine set_selector

    subroutine destroy(coordinates)
        class(Abstract_Complete_Coordinates_Writer), allocatable, intent(inout) :: coordinates

        if (allocated(coordinates)) then
            call coordinates%destroy()
            deallocate(coordinates)
        end if
    end subroutine destroy

end module procedures_complete_coordinates_writer_factory
