﻿#include "YaguiUdaAntennaTemplate.h"
#include <GC_MakeSegment.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepPrimAPI_MakeTorus.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Solid.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Face.hxx>
#include <TopTools_MapOfShape.hxx>
#include <BRepAlgoAPI_BuilderAlgo.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <STEPControl_Writer.hxx>
#include <TopExp_Explorer.hxx>
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepBndLib.hxx>
#include <map>
#include <filesystem>
#include "easylogging++/easylogging++.h"
#include <TopTools_IndexedMapOfShape.hxx>
#include "topology/ShapeAlgorithms.h"
#include "vtkForCenos/topologyToVTK.h"
#include "misc/miscFunctions.hpp"
#include "mesh/MeshGenerator.h"
#include "mesh/AutoMeshSize.h"

namespace nglib {
#include "nglib.h"
}


YaguiUdaAntennaTemplate::YaguiUdaAntennaTemplate(std::string path) : BasicTemplate(path)
{
    type = YAGUI_UDA_ANTENNA;
}

void YaguiUdaAntennaTemplate::parseInputJSON(json* j)
{
    json& data = *j;
    name = data["name"].get<std::string>();
    boom_length = data["properties"]["boom_length"].get<double>() / 2.0;
    boom_width = data["properties"]["boom_width"];
    feed_length = data["properties"]["feed_length"];
    feed_radius = data["properties"]["feed_radius"];
    reflector_length = data["properties"]["reflector_length"].get<double>();
    reflector_radius = data["properties"]["reflector_radius"].get<double>();
    reflector_distance = data["properties"]["reflector_distance"];
    has_trombone = data["properties"]["hasTrombone"];
    if (has_trombone) {
        trombone_inner_radius = data["properties"]["trombone_inner_radius"];
        trombone_gap = data["properties"]["trombone_gap"];
    }
    else {
        trombone_inner_radius = 0;
        trombone_gap = 0;
    }
    //possible parameters to be added if needed.
    double trombone_center = 0;
    double trombone_angle = 90;

    director_radius = data["properties"]["director_radius"];
    director_distance = data["properties"]["director_distance"];
    director_separation = data["properties"]["director_separation"];
    director_number = 0;
    json& data2 = data["properties"]["directors_length"];
    for (json::iterator it = data2.at("value").begin(); it != data2.at("value").end(); ++it) {
        ++it;
        directors_length.push_back(it.value().get<double>());
        director_number++;
    }
}

TopoDS_Face YaguiUdaAntennaTemplate::makeFeed()
{
    //feed - only add to faceMap for recognition
    gp_Pnt fPnt[4] = { gp_Pnt(feed_radius, 0 - trombone_inner_radius, boom_width / 2),
                        gp_Pnt(-feed_radius, 0 - trombone_inner_radius, boom_width / 2),
                        gp_Pnt(-feed_radius, 0 - trombone_inner_radius, -boom_width / 2),
                        gp_Pnt(feed_radius, 0 - trombone_inner_radius, -boom_width / 2) };
    BRepBuilderAPI_MakeWire fWire;
    for (int i = 0; i < 4; i++)
    {
        Handle(Geom_TrimmedCurve) fSegment = GC_MakeSegment(fPnt[i], fPnt[i == 3 ? 0 : i + 1]);
        TopoDS_Edge fEdge = BRepBuilderAPI_MakeEdge(fSegment);
        fWire.Add(fEdge);
    }
    TopoDS_Face feed = BRepBuilderAPI_MakeFace(fWire.Wire());
    return feed;
}

TopoDS_Solid YaguiUdaAntennaTemplate::makeTopCylinder()
{
    gp_Pnt ptTop = gp_Pnt(0, 0 - trombone_inner_radius, boom_width / 2);
    gp_Dir vz = gp_Dir(0, 0, 1);
    gp_Dir vx = gp_Dir(1, 0, 0);

    gp_Ax2 axis_top = gp_Ax2(ptTop, vz, vx);
    TopoDS_Solid top_cylinder = BRepPrimAPI_MakeCylinder(axis_top, feed_radius, feed_length - boom_width / 2);
    return top_cylinder;

}

TopoDS_Solid YaguiUdaAntennaTemplate::makeTopCylinderLoop()
{
    gp_Pnt ptTop = gp_Pnt(0, trombone_inner_radius, trombone_gap / 2);
    gp_Dir vz = gp_Dir(0, 0, 1);
    gp_Dir vx = gp_Dir(1, 0, 0);

    gp_Ax2 axis_top = gp_Ax2(ptTop, vz, vx);
    TopoDS_Solid top_cylinder_loop = BRepPrimAPI_MakeCylinder(axis_top, feed_radius, feed_length - trombone_gap / 2);
    return top_cylinder_loop;

}

TopoDS_Solid YaguiUdaAntennaTemplate::makeTopCylinderTorus()
{

    gp_Pnt ptTop = gp_Pnt(0, 0, feed_length);
    gp_Dir vy = gp_Dir(0, 1, 0);
    gp_Dir vx = gp_Dir(1, 0, 0);

    gp_Ax2 axis_top = gp_Ax2(ptTop, vx, vy);
    //TopoDS_Solid top_cylinder_torus = BRepPrimAPI_MakeCylinder(axis_top, feed_radius, feed_length - boom_width / 2);
    TopoDS_Solid top_cylinder_torus = BRepPrimAPI_MakeTorus(axis_top, trombone_inner_radius, feed_radius, 3.14);
    return top_cylinder_torus;

}

TopoDS_Solid YaguiUdaAntennaTemplate::makeBottomCylinder()
{
    gp_Pnt ptBot = gp_Pnt(0, 0 - trombone_inner_radius, -feed_length);
    gp_Dir vz = gp_Dir(0, 0, 1);
    gp_Dir vx = gp_Dir(1, 0, 0);

    gp_Ax2 axis_bot = gp_Ax2(ptBot, vz, vx);
    TopoDS_Solid bot_cylinder = BRepPrimAPI_MakeCylinder(axis_bot, feed_radius, feed_length - boom_width / 2);
    return bot_cylinder;
}

TopoDS_Solid YaguiUdaAntennaTemplate::makeBottomCylinderLoop()
{
    gp_Pnt ptBot = gp_Pnt(0, trombone_inner_radius, -trombone_gap / 2);
    gp_Dir vz = gp_Dir(0, 0, -1);
    gp_Dir vx = gp_Dir(1, 0, 0);

    gp_Ax2 axis_bot = gp_Ax2(ptBot, vz, vx);
    TopoDS_Solid bot_cylinder_loop = BRepPrimAPI_MakeCylinder(axis_bot, feed_radius, feed_length - trombone_gap / 2);
    return bot_cylinder_loop;
}

TopoDS_Solid YaguiUdaAntennaTemplate::makeBottomCylinderTorus()
{
    //R1 = 10
    gp_Pnt ptTop = gp_Pnt(0, 0, -feed_length);
    gp_Dir vy = gp_Dir(0, 1, 0);
    gp_Dir vx = gp_Dir(-1, 0, 0);

    gp_Ax2 axis_top = gp_Ax2(ptTop, vx, vy);

    TopoDS_Solid bottom_cylinder_torus = BRepPrimAPI_MakeTorus(axis_top, trombone_inner_radius, feed_radius, 3.14);
    return bottom_cylinder_torus;

}

TopoDS_Solid YaguiUdaAntennaTemplate::makeFeedCylinder()
{
    gp_Pnt ptGap = gp_Pnt(0, 0 - trombone_inner_radius, -boom_width / 2);
    gp_Dir vz = gp_Dir(0, 0, 1);
    gp_Dir vx = gp_Dir(1, 0, 0);

    gp_Ax2 axis_gap = gp_Ax2(ptGap, vz, vx);
    TopoDS_Solid gap_cylinder = BRepPrimAPI_MakeCylinder(axis_gap, feed_radius, boom_width);
    return gap_cylinder;
}

TopoDS_Solid YaguiUdaAntennaTemplate::makeReflectorCylinder()
{
    gp_Pnt ptBot = gp_Pnt(-reflector_distance, 0, -reflector_length / 2);
    gp_Dir vz = gp_Dir(0, 0, 1);
    gp_Dir vx = gp_Dir(1, 0, 0);

    gp_Ax2 axis_bot = gp_Ax2(ptBot, vz, vx);
    TopoDS_Solid reflector_cylinder = BRepPrimAPI_MakeCylinder(axis_bot, reflector_radius, reflector_length);
    return reflector_cylinder;
}




TopTools_ListOfShape YaguiUdaAntennaTemplate::makeDirectors3()
{


    TopTools_ListOfShape directors_list;
    for (int i = 0; i < director_number; i++)
    {
        gp_Pnt ptBot = gp_Pnt(director_distance * (i + 1), 0, -directors_length.at(i) / 2);
        gp_Dir vz = gp_Dir(0, 0, 1);
        gp_Dir vx = gp_Dir(1, 0, 0);

        gp_Ax2 axis_bot = gp_Ax2(ptBot, vz, vx);
        TopoDS_Solid director_cylinder = BRepPrimAPI_MakeCylinder(axis_bot, director_radius, directors_length.at(i));
        directors_list.Append(director_cylinder);
    }
    return directors_list;
}


void YaguiUdaAntennaTemplate::generateGeometry()
{
    if (progress != nullptr) {
        progress->sendLog("Generating Yagui Uda template geometry ");
    }

    TopoDS_Shape top_cylinder = makeTopCylinder();
    TopoEntity_ top_cylinder_ent = std::make_shared<TopoEntity>(top_cylinder, "top_cylinder_ent");
    top_cylinder_ent->setEnabled(false);
    geom_data->addEntity(top_cylinder_ent);

    TopoDS_Shape top_cylinder_loop;
    TopoDS_Shape top_cylinder_torus;
    TopoDS_Shape bot_cylinder_loop;
    TopoDS_Shape bottom_cylinder_torus;

    if (has_trombone) {
        top_cylinder_loop = makeTopCylinderLoop();
        TopoEntity_ top_cylinder_loop_ent = std::make_shared<TopoEntity>(top_cylinder_loop, "top_cylinder_loop_ent");
        top_cylinder_loop_ent->setEnabled(false);
        geom_data->addEntity(top_cylinder_loop_ent);


        top_cylinder_torus = makeTopCylinderTorus();
        TopoEntity_ top_cylinder_torus_ent = std::make_shared<TopoEntity>(top_cylinder_torus, "top_cylinder_torus_ent");
        top_cylinder_torus_ent->setEnabled(false);
        geom_data->addEntity(top_cylinder_torus_ent);

        bot_cylinder_loop = makeBottomCylinderLoop();
        TopoEntity_ bot_cylinder_loop_ent = std::make_shared<TopoEntity>(bot_cylinder_loop, "bot_cylinder_loop_ent");
        bot_cylinder_loop_ent->setEnabled(false);
        geom_data->addEntity(bot_cylinder_loop_ent);

        bottom_cylinder_torus = makeBottomCylinderTorus();
        TopoEntity_ bottom_cylinder_torus_ent = std::make_shared<TopoEntity>(bottom_cylinder_torus, "bottom_cylinder_torus_ent");
        bottom_cylinder_torus_ent->setEnabled(false);
        geom_data->addEntity(bottom_cylinder_torus_ent);

    }



    TopoDS_Shape bot_cylinder = makeBottomCylinder();
    TopoEntity_ bot_cylinder_ent = std::make_shared<TopoEntity>(bot_cylinder, "bot_cylinder_ent");
    bot_cylinder_ent->setEnabled(false);
    geom_data->addEntity(bot_cylinder_ent);




    TopoDS_Shape feed_cylinder = makeFeedCylinder();
    TopoEntity_ feed_cylinder_ent = std::make_shared<TopoEntity>(feed_cylinder, "feed_cylinder_ent");
    feed_cylinder_ent->setEnabled(false);
    geom_data->addEntity(feed_cylinder_ent);


    TopoDS_Shape reflector_cylinder = makeReflectorCylinder();
    TopoEntity_ reflector_cylinder_ent = std::make_shared<TopoEntity>(reflector_cylinder, "reflector_cylinder_ent");
    reflector_cylinder_ent->setEnabled(false);
    geom_data->addEntity(reflector_cylinder_ent);

    TopTools_ListOfShape directors3 = makeDirectors3();
    int directorOrder = 0;
    for (auto shape : directors3) {

        TopoDS_Shape director_cylinder = shape;
        TopoEntity_ director_cylinder_ent = std::make_shared<TopoEntity>(director_cylinder, "director_cylinder_ent" + directorOrder);
        director_cylinder_ent->setEnabled(false);
        geom_data->addEntity(director_cylinder_ent);
        directorOrder++;
    }


    TopTools_ListOfShape pecList;
    // add faces of top cylinder to pecList
    // except bottom surface
    {

        Bnd_Box box;
        box.SetGap(0.0);
        BRepBndLib::Add(top_cylinder, box);
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
        for (TopExp_Explorer faceExplorer(top_cylinder, TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
        {
            TopoDS_Shape current = faceExplorer.Current();

            // if it is lower surface, skip
            GProp_GProps gprops1;
            BRepGProp::SurfaceProperties(current, gprops1);
            if (abs(gprops1.CentreOfMass().Z() - zmin) < 1e-5)
                continue;

            pecList.Append(current);

            // if it is upper surface, skip


            if (abs(gprops1.CentreOfMass().Z() - zmax) < 1e-5)
                continue;

            pecList.Append(current);
        }
    }




    {
        Bnd_Box box;
        box.SetGap(0.0);
        BRepBndLib::Add(bot_cylinder, box);
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
        for (TopExp_Explorer faceExplorer(bot_cylinder, TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
        {
            TopoDS_Shape current = faceExplorer.Current();

            // if it is upper surface, skip
            GProp_GProps gprops1;
            BRepGProp::SurfaceProperties(current, gprops1);
            if (abs(gprops1.CentreOfMass().Z() - zmax) < 1e-5)
                continue;

            pecList.Append(current);

            // if it is lower surface, skip


            if (abs(gprops1.CentreOfMass().Z() - zmin) < 1e-5)
                continue;

            pecList.Append(current);


        }
    }

    {
        Bnd_Box box;
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        if (has_trombone) {
            box.SetGap(0.0);
            BRepBndLib::Add(top_cylinder_loop, box);

            box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
            for (TopExp_Explorer faceExplorer(top_cylinder_loop, TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
            {
                TopoDS_Shape current = faceExplorer.Current();

                // if it is upper surface, skip
                GProp_GProps gprops1;
                BRepGProp::SurfaceProperties(current, gprops1);
                if (abs(gprops1.CentreOfMass().Z() - zmax) < 1e-5)
                    continue;

                pecList.Append(current);

            }
        }
    }
    // for loop of upper feed cylinder
    {
        Bnd_Box box;
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        box.SetGap(0.0);
        BRepBndLib::Add(top_cylinder_torus, box);
        if (has_trombone) {
            box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
            for (TopExp_Explorer faceExplorer(top_cylinder_torus, TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
            {
                TopoDS_Shape current = faceExplorer.Current();

                // if it is lower surface, skip
                GProp_GProps gprops1;
                BRepGProp::SurfaceProperties(current, gprops1);
                if (abs(gprops1.CentreOfMass().Z() - zmin) < 1e-5)
                    continue;

                pecList.Append(current);

            }
        }
    }
    {
        Bnd_Box box;
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        box.SetGap(0.0);
        BRepBndLib::Add(bot_cylinder_loop, box);
        if (has_trombone) {
            box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
            for (TopExp_Explorer faceExplorer(bot_cylinder_loop, TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
            {
                TopoDS_Shape current = faceExplorer.Current();

                // if it is lower surface, skip
                GProp_GProps gprops1;
                BRepGProp::SurfaceProperties(current, gprops1);
                if (abs(gprops1.CentreOfMass().Z() - zmin) < 1e-5)
                    continue;

                pecList.Append(current);
            }
        }
    }

    {
        Bnd_Box box;
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        box.SetGap(0.0);
        BRepBndLib::Add(bottom_cylinder_torus, box);
        if (has_trombone) {
            box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
            for (TopExp_Explorer faceExplorer(bottom_cylinder_torus, TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
            {
                TopoDS_Shape current = faceExplorer.Current();

                // if it is upper surface, skip
                GProp_GProps gprops1;
                BRepGProp::SurfaceProperties(current, gprops1);
                if (abs(gprops1.CentreOfMass().Z() - zmax) < 1e-5)
                    continue;

                pecList.Append(current);
            }
        }
    }

    {
        Bnd_Box box;
        box.SetGap(0.0);
        BRepBndLib::Add(reflector_cylinder, box);
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
        for (TopExp_Explorer faceExplorer(reflector_cylinder, TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
        {
            TopoDS_Shape current = faceExplorer.Current();
            pecList.Append(current);
        }
    }

    /*for (int i = 0; i < director_number; i++)
    {
        Bnd_Box box;
        box.SetGap(0.0);
        BRepBndLib::Add(*(directors + i), box);
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
        for (TopExp_Explorer faceExplorer(*(directors + i), TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
        {
            TopoDS_Shape current = faceExplorer.Current();
            pecList.Append(current);
        }
    }*/

    for (auto director : directors3) {
        Bnd_Box box;
        box.SetGap(0.0);
        BRepBndLib::Add(director, box);
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
        for (TopExp_Explorer faceExplorer(director, TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
        {
            TopoDS_Shape current = faceExplorer.Current();
            pecList.Append(current);
        }
    }

    BoundaryGroup_ pec_group = std::make_shared<BoundaryGroup>();
    pec_group->setName("wire_surface");
    pec_group->setLabel("Wire Surface");
    pec_group->setRole("wire");

    int sh_nr = 0;
    for (auto sh : pecList)
    {
        std::string ent_name = "pec_face_" + std::to_string(++sh_nr);
        TopoEntity_ ent = std::make_shared<TopoEntity>(sh, ent_name);
        geom_data->addEntity(ent);
        pec_group->addEntity(ent);
    }
    pec_group->update();
    geom_data->addBoundaryGroup(pec_group);


    TopoDS_ListOfShape feedList;
    {
        Bnd_Box box;
        box.SetGap(0.0);
        BRepBndLib::Add(feed_cylinder, box);
        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
        box.Get(xmin, ymin, zmin, xmax, ymax, zmax);
        for (TopExp_Explorer faceExplorer(feed_cylinder, TopAbs_ShapeEnum::TopAbs_FACE); faceExplorer.More(); faceExplorer.Next())
        {
            TopoDS_Shape current = faceExplorer.Current();

            // if it is upper surface, skip
            GProp_GProps gprops1;
            BRepGProp::SurfaceProperties(current, gprops1);
            if (abs(gprops1.CentreOfMass().Z() - zmax) < 1e-5)
                continue;

            if (abs(gprops1.CentreOfMass().Z() - zmin) < 1e-5)
                continue;

            feedList.Append(current);
        }
    }

    BoundaryGroup_ feed_group = std::make_shared<BoundaryGroup>();
    feed_group->setName("feed");
    feed_group->setLabel("Port");
    feed_group->setRole("feed");

    sh_nr = 0;
    for (auto sh : feedList)
    {
        std::string ent_name = "feed_face_" + std::to_string(++sh_nr);
        TopoEntity_ ent = std::make_shared<TopoEntity>(sh, ent_name);
        geom_data->addEntity(ent);
        feed_group->addEntity(ent);
    }
    feed_group->update();
    geom_data->addBoundaryGroup(feed_group);

}

void YaguiUdaAntennaTemplate::assignMeshSizes(MeshGenerator_ mg, GeometryData_ gd, double mesh_density_factor, double global_max)
{
    // Manual meshing part. Automatic meshing works inconsistently for dipole antenna template.
    // Will switch back to AMS when it is fixed
    // THIS PART IS EMPIRICAL! There is no theory behind element sizes

    double maxh_global = global_max;
    double minh_global = std::min(feed_radius, boom_width);

    //refinement on faces
    std::shared_ptr<MeshParameters> mp1 = std::make_shared<MeshParameters>();
    double maxh_local = std::min(global_max / 2, feed_radius) / 3;
    double minh_local = std::min(feed_radius, boom_width) / 4;

    if (minh_local * 1.5 > maxh_local)
        minh_local = minh_local / 2;

    mp1->setMaxH(maxh_local * mesh_density_factor);
    mp1->setMinH(minh_local * mesh_density_factor);

    // set mp1 for all wire and feed entities
    auto feed_group = gd->getBoundaryByName("feed");
    auto wire_group = gd->getBoundaryByName("wire_surface");

    for (auto ent : feed_group->getEntities())
    {
        mg->setParameters(mp1, ent);
        for (auto subent : gd->getEntities())
        {
            if (subent->getType() != ShapeType::EDGE)
                continue;
            if (subent->isSubShapeOf(ent))
                mg->setParameters(mp1, subent);
        }
    }

    for (auto ent : wire_group->getEntities())
    {
        mg->setParameters(mp1, ent);
        for (auto subent : gd->getEntities())
        {
            if (subent->getType() != ShapeType::EDGE)
                continue;
            if (subent->isSubShapeOf(ent))
                mg->setParameters(mp1, subent);
        }
    }

}

bool YaguiUdaAntennaTemplate::validate(std::string& msg)
{

    const int MAX_RATIO = 350;
    int ratio = (int)(((2 * feed_length) / feed_radius) / 2);

    if (ratio > MAX_RATIO)
    {
        msg = "The diameter to length ratio is too large(1:" + std::to_string(ratio) + ").Please do not exceed 1:" + std::to_string(MAX_RATIO);
        return false;
    }


    if (feed_length <= 0)
    {
        msg = "Wire length should be positive number.";
        return false;
    }

    if (feed_length <= 0)
    {
        msg = "Feed gap should be positive number.";
        return false;
    }

    if (feed_length <= 0)
    {
        msg = "Wire radius should be positive number.";
        return false;
    }

    if (2 * feed_length <= boom_width)
    {
        msg = "Use shorter gap!";
        return false;
    }

    return true;
}

