<?php

function GetMarkByComment(string $Comment): int
{
  global $Database;

  $DbResult = $Database->query('SELECT `Id` FROM `NetworkMark` WHERE `Comment`="'.$Comment.'"');
  if ($DbResult->num_rows > 0)
  {
    $DbRow = $DbResult->fetch_assoc();
    return $DbRow['Id'];
  } else
  {
    $DbResult = $Database->query('INSERT INTO `NetworkMark` (`Comment`) VALUES ("'.$Comment.'")');
    return $Database->insert_id;
  }
}

function GetSubgroupByRange(string $AddressRange): int
{
  global $Database;

  $DbResult = $Database->query('SELECT `Id` FROM `NetworkMangleSubgroup` WHERE `AddressRange`="'.$AddressRange.'"');
  if ($DbResult->num_rows > 0)
  {
    $DbRow = $DbResult->fetch_assoc();
    return $DbRow['Id'];
  } else
  {
    $DbResult = $Database->query('INSERT INTO `NetworkMangleSubgroup` (`AddressRange`) VALUES ("'.$AddressRange.'")');
    return $Database->insert_id;
  }
}

function InsertToAddressTreeIPv4(array &$Tree, NetworkAddressIPv4 $Address, string $Name, bool $InterSubnets = false, bool $ForceMark = false)
{
  global $Config;

  $Found = false;
  foreach ($Tree['Items'] as $Index => $Node)
  {
    if ($Node['Address']->Contain($Address))
    {
      InsertToAddressTreeIPv4($Tree['Items'][$Index], $Address, $Name, true);
      $Found = true;
    }
  }
  if ($Found == false)
  {
    if ($InterSubnets and ($Tree['Address']->Prefix < $Config['MainRouter']['MangleRuleSubgroupMinPrefix']) and
    ($Address->Prefix > ($Tree['Address']->Prefix + 1)))
    {
      $NewAddress = new NetworkAddressIPv4();
      $NewAddress->Address = $Address->Address;
      $NewAddress->ChangePrefix($Tree['Address']->Prefix + 1);
      $Tree['Items'][] = array('Address' => $NewAddress, 'Name' => $Name, 'Items' => array(), 'ForceMark' => false);
      InsertToAddressTreeIPv4($Tree['Items'][count($Tree['Items']) - 1], $Address, $Name, true);
    } else
    {
      $NewNode = array('Address' => $Address, 'Name' => $Name, 'Items' => array(), 'ForceMark' => $ForceMark);

      // Should be existed items placed under new node?
      $Found = false;
      foreach ($Tree['Items'] as $Index => $Node)
      {
        if (($Node['Address']->Address == $NewNode['Address']->Address) and
        ($Node['Address']->Prefix == $NewNode['Address']->Prefix)) $Found = true;

        if ($Address->Contain($Node['Address']))
        {
          $NewNode['Items'][] = $Node;
          unset($Tree['Items'][$Index]);
        }
      }
      if ($Found == false) $Tree['Items'][] = $NewNode;
    }
  }
}

function InsertToAddressTreeIPv6(array &$Tree, NetworkAddressIPv6 $Address, string $Name, bool $InterSubnets = false, bool $ForceMark = false)
{
  global $Config;

  $Found = false;
  foreach ($Tree['Items'] as $Index => $Node)
  {
    if ($Node['Address']->Contain($Address))
    {
      InsertToAddressTreeIPv6($Tree['Items'][$Index], $Address, $Name, true);
      $Found = true;
    }
  }
  if ($Found == false)
  {
    if ($InterSubnets and ($Tree['Address']->Prefix < $Config['MainRouter']['MangleRuleSubgroupMinPrefix']) and
    ($Address->Prefix > ($Tree['Address']->Prefix + 1)))
    {
      $NewAddress = new NetworkAddressIPv6();
      $NewAddress->Address = $Address->Address;
      $NewAddress->ChangePrefix($Tree['Address']->Prefix + 1);
      $Tree['Items'][] = array('Address' => $NewAddress, 'Name' => $Name, 'Items' => array(), 'ForceMark' => false);
      InsertToAddressTreeIPv6($Tree['Items'][count($Tree['Items']) - 1], $Address, $Name, true);
    } else
    {
      $NewNode = array('Address' => $Address, 'Name' => $Name, 'Items' => array(), 'ForceMark' => $ForceMark);

      // Should be existed items placed under new node?
      $Found = false;
      foreach ($Tree['Items'] as $Index => $Node)
      {
        if (($Node['Address']->Address == $NewNode['Address']->Address) and
        ($Node['Address']->Prefix == $NewNode['Address']->Prefix)) $Found = true;

        if ($Address->Contain($Node['Address']))
        {
          $NewNode['Items'][] = $Node;
          unset($Tree['Items'][$Index]);
        }
      }
      if ($Found == false) $Tree['Items'][] = $NewNode;
    }
  }
}

function ShowSubnetNode(array $Node, int $Indent = 0): void
{
  echo(str_repeat('  ', $Indent).$Node['Address']->AddressToString().'/'.$Node['Address']->Prefix.' '.$Node['Name']."\n");
  foreach ($Node['Items'] as $Index => $Item)
  {
    ShowSubnetNode($Item, $Indent + 1);
  }
}
