(*~\Глагол\Отделы\Иное\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(**)                             ОТДЕЛ СтэкСлеД;
(*============================================================================*)
(* НАЗНАЧЕНИЕ:                                                                *
//              обработка одноконцевого цепного списка-набора (стэк)          *
//                               вида  СтэкСлеД.нСписок                       *
//     из односвязных звеньев-наборов  СтэкСлеД.ДкЗвену_телоД                 *
// с доступом <слеД> и полиморфным доступом <телоД:СтэкСлеД.ДкПустомуНабору>  *
//                                                                            *
//       LIFO           N+1 -> N -> ... -> 2 -> 1 -> ПУСТО                    *
//             ВхВых <=> начЗвенД                                             *
//                                                                            *
//       Абстрактные Виды Данных (АВД) и многоформие                          *
//                при Предметно-описательном Подходе (ПоП) на Глаголе         *
//                                                     или на Обероне         *
//     [ Абстрактные Типы Данных (АТД) и полиморфизм                          *
//                при традиционном ООП               ]                        *)
(*============================================================================*)

ВИД
                           (*--- опорный вид для <телоД> в звене ---*)

  ДкПустомуНабору- = ДОСТУП К нПустой;
                              нПустой- = НАБОР КОН;  (* пустой набор "СтэкСлеД.нПустой" - расширяемый
                                                        для конкретных тел у звеньев списка, т.е. это опорный вид *)

(*----------------------------------------------------------------------------*
//
//     Отдел СтэкСлеД содержит конструкцию для работы со стэком из звеньев, 
// связанных через <слеД> - по доступу только к следующему звену
/                                (цепной список звеньев или связанный список).
//
 * Скрытый реальный вид-НАБОР: 'нЗвено'     - односвязное звено-телоД_СлеД    *
 *       Реальный  вид-ДОСТУП: "ДкЗвену_телоД" - доступ к звену-телоД_СлеД    *
//                                                                            *
//       LIFO           N+1 -> N -> ... -> 2 -> 1 -> ПУСТО                    *
//             ВхВых <=> начЗвенД                                             *
//                                                                            *
 *----------------------------------------------------------------------------*)
(*-
    Описание экспортируемого/общедоступного/
                                 публичного/видимого доступа к НАБОРу-предмету
             <ДкЗвену_телоД>
  с доступом <телоД+> к набору пока пустому - опорному (будущие данные звена) и
  с доступом <слеД+>  к следующему звену связанного списка стэк-СлеД/очередь-СлеД.
-*)
  ДкЗвену_телоД- = ДОСТУП К (*нЗвено;
                              нЗвено =*) (* односвязное звено-СлеД связанного списка *)
(*
   Вид набор-звено <нЗвено> НЕ нужно расширять! Поэтому хватит только вида <ДкЗвену_телоД-> "ДОСТУП К",
   т.к. память под наборы-звенья выделяется внутри задачи ДобавитьНовЗвеноВначСписка(нСписок,данныеД)
                                         [ СОЗДАТЬ(звеноД) и добавить в конец списка ]
*)
  НАБОР
    телоД+ :ДкПустомуНабору;  (* доступ к пустому набору, описанному именно в этом отделе! - опорный вид *)
     слеД+ :ДкЗвену_телоД     (* доступ к следующему звену *)
  КОН;
(*------------------------------------------------*
//
//     Вид-Доступ <СтэкСлеД.ДкЗвену_телоД> к виду набор-звено НЕ нужно расширять
//                                             (или наследовать в терминологии традиционного ООП),
// т.к. он обеспечивает навигацию по звеньям любого списка-стэка в приложении на Глаголе,
// например:
-----------------------------------------------
ПЕР
  звеноД:СтэкСлеД.ДкЗвену_телоД;    (* доступ к звену (со ссылкой <слеД> и <телоД>) списка-стэка *)

  список:СтэкСлеД.нСписок;          (* набор-список - стэк из звеньев со ссылкой <слеД> *)
    ...
УКАЗ
  звеноД:=список.начЗвенД;           (* доступ к   N-му     звену стэка-СлеД *)

  звеноД:=звеноД.слеД;               (* доступ к следующему звену стэка-СлеД *)
    ...
-----------------------------------------------

//
 *------------------------------------------------*)

ВИД
(*----------------------------------------------------------------------------*
 *    Реальный вид-НАБОР:   'нСписок' - стэк/магазин с головой   (ВхВых) -    *
 *       LIFO - последним вошёл, 1-вым вышел                 [Втолкнуть/push, *
 *                                                              Забрать/pop]  *
 *            вид-ДОСТУП: 'ДкСписку' - доступ к списку стэк-СлеД              *
//                                                                            *
//       LIFO           N+1 -> N -> ... -> 2 -> 1 -> ПУСТО                    *
//             ВхВых <=> начЗвенД                                             *
//                                                                            *
 *  Одноконцевой цепной набор-список 'нСписок' - это стэк/магазин с головой   *
 *    из односвязных звеньев с доступом к следующему звену.                   *
 *                                                                            *
 *  Добавление нового звена происходит в начало-голову стэка - <начЗвенД+>, LIFO *
 *   а удаление звена возможно только из начала-головы стэка - <начЗвенД+>.   FO *
 *----------------------------------------------------------------------------*)
(*-
    Описание экспортируемого/общедоступного/
                                 публичного/видимого НАБОРа-предмета -
               <нСписок>
  со счётчиком <всехЗвен+> входящих в цепной список и
    с доступом  <начЗвенД+>  к  N-му (LIFO)  звену связанного списка 'нСписок'.
-*)
  ДкСписку- = ДОСТУП К нСписок;
                       нСписок- =
  НАБОР
      всехЗвен+ :ЦЕЛ;
       начЗвенД+:ДкЗвену_телоД   (* ссылка на голову списка-набора "СтэкСлеД.нСписок" или с доступом вида "СтэкСлеД.ДкСписку" *)
  КОН;

(*------------------------------------------------*
//
//     Вид-Набор  <СтэкСлеД.нСписок> НЕ нужно расширять!
// или
//     Вид-Доступ <СтэкСлеД.ДкСписку> к виду набор-список НЕ нужно расширять
//                                                           (или наследовать в терминологии традиционного ООП),
// т.к. он обеспечивает навигацию для любого списка-стэка в приложении на Глаголе.
//
//     Однако, память под наборы-списки НЕ выделяется внутри задач и нужно явно записать:
//
-----------------------------------------------
ПЕР
  отделыCПредкамиД,                         (* доступ  к списку-набору - список отделов с известными предками *)
  отделыНаОбработкуД:СтэкСлеД.ДкСписку;     (* доступ  к списку-набору - список отделов на обработку          *)
    ...
УКАЗ
  СОЗДАТЬ(отделыCПредкамиД);     (* создаём по доступу к списку-набору - список отделов с известными предками *)
  СОЗДАТЬ(отделыНаОбработкуД);   (* создаём по доступу к списку-набору - список отделов на обработку          *)
-----------------------------------------------
       или
-----------------------------------------------
ПЕР
  отделыCПредками,                                    (* список-набор  - список отделов с известными предками *)
  отделыНаОбработку:СтэкСлеД.нСписок;                 (* список-набор  - список отделов на обработку          *)
-----------------------------------------------
//
//  Поэтому НЕ хватит только вида "ДОСТУП К" и лучше использовать пока вид-набор СтэкСлеД.нСписок
//
//     А вот доступ к конкретному телу звена (полимофизм или многоформие) реализуется
// в приложении на Глаголе, например, таким преобразованием:
//
-----------------------------------------------
ВИД              (*
                     вид-доступ к телу звена в списке отделов
                  *)
  ДкФайлуОтдела = ДОСТУП К НАБОР (СтэкСлеД.нПустой)       (* расширяем (наследуем) доступ к пустому набору,
                                              т.к. доступ к телу звена <телоД> имеет именно этот же опорный вид!
                                                                       <телоД:СтэкСлеД.ДкПустомуНабору>
                                                           *)
    .новые поля-свойства.
                           КОН; (* доступа <ДкФайлуОтдела> *)
    ...
ПЕР
  отделД:ДкФайлуОтдела;                     (* доступ  к отделу = телу звена *)

  отделыCПредкамиД,                         (* доступ  к списку-набору - список отделов с известными предками *)
  отделыНаОбработкуД:СтэкСлеД.ДкСписку;     (* доступ  к списку-набору - список отделов на обработку          *)
    ...
              звеноД:СтэкСлеД.ДкЗвену_телоД; (* доступ к звену, содержащему доступ к телу звена *)
    ...
           отдИмяФ  :Файл.ВПолного;
    ...
УКАЗ
  СОЗДАТЬ(отделыCПредкамиД);     (* создаём по доступу к списку-набору - список отделов с известными предками *)
  СОЗДАТЬ(отделыНаОбработкуД);   (* создаём по доступу к списку-набору - список отделов на обработку          *)
    ...
(*
   Обход списка с N-го звена до 1-го, т.е. пока звеноД.слеД # ПУСТО
 *)
    ...
-----------------------------------------------
                          или
-----------------------------------------------
    ...
ПЕР
  отделыCПредками,                                    (* список-набор  - список отделов с известными предками *)
  отделыНаОбработку:СтэкСлеД.нСписок;                 (* список-набор  - список отделов на обработку          *)
    ...
              звеноД:СтэкСлеД.ДкЗвену_телоД; (* доступ к звену, содержащему доступ к телу звена *)
    ...
           отдИмяФ  :Файл.ВПолного;
    ...
УКАЗ
(*
   Обход списка с N-го звена до 1-го, т.е. пока звеноД.слеД # ПУСТО
 *)
              звеноД:=отделыCПредкамиД.начЗвенД;              (* доступ к N-му звену стэка *)
      (*
//       LIFO                  N -> ... -> 2 -> 1 -> ПУСТО
//             ВхВых <=> начЗвенД
         или
              звеноД:=СтэкСлеД.ДкNмуЗвену(отделыCПредками);   (* доступ к N-му звену стэка *)
       *)
(*         в <звеноД.телоД> уже находится доступ к телу - <отделД:ДкФайлуОтдела>           *)
  ПОКА
              звеноД # ПУСТО
  ВЫП                                                             (* преобразование полиморфное  
                     телоД               из СтэкСлеД.ДкПустомуНабору
                           ДкФайлуОтдела <- СтэкСлеД.ДкПустомуНабору                       *)
      отделД:=звеноД.телоД(ДкФайлуОтдела);  
    ...

    ЕСЛИ
      отделД.имяФ^ = отдИмяФ 
    ТО
      ЕСЛИ

      отделД.время = МИН(Файл.шцВремя)

      ТО
        ОО.Ошибка(ОО.ПЕРЕКРЕСТНОЕ_ИСПОЛЬЗОВАНИЕ)
      КОН;
      ВОЗВРАТ отделД
    КОН;

    звеноД:=звеноД.слеД
  КОН;
    ...
                   (* создаём и запоминаем новый <отделД> - доступ к отделу = телу звена *)
  ЕСЛИ
      НЕ Файл.Существует(отдИмяФ)
  ТО
    ОО.Отметить(ОО.ФАЙЛ_НЕ_ОТКРЫВАЕТСЯ,отдИмяФ)
  КОН;
  СОЗДАТЬ(отделД);
    ...

   (* создаём новое <звеноД> (с доступом к телоД=отделД) внутри задачи СтэкСлеД.ДобавитьНовЗвеноВначСписка(..)
                                                                    и присоединяем это звено к концу списка звеньев *)
  СтэкСлеД.ДобавитьНовЗвеноВначСписка(отделыCПредками,отделД);
    ...

КОН ЗП.
//
 *------------------------------------------------*)

(*------------------------------------------------*
//
//       Таким образом, вся навигация по списку звеньев (содержащих полиморфный доступ к телу звена <телоД>)
// происходит внутри отдела, в котором собственно и описан вид набор-список    - СтэкСлеД.нСписок
//                                                    или  вид доступ к набору - СтэкСлеД.ДкСписку 
//
 *------------------------------------------------*)


(*=рррррррррррррррррррррррр= реализация задач =рррррррррррррррррррррррррррррр=*)


(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА                                                                       (* (СтэкСлеД.нСписок) *)
       ОчиститьСписок-(список+:нСписок);
    (* ОчиститьСписок-(стэкД+:ДкСписку); *)
УКАЗ
              ОБНУЛИТЬ(список)   
           (* ОБНУЛИТЬ(стэкД^) *)   
               (*
                       список.всехЗвен :=0;
                        список.начЗвенД:=ПУСТО
                *)
КОН ОчиститьСписок;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА                                                                       (* (СтэкСлеД.нСписок) *)
       ДобавитьНовЗвеноВначСписка-(
                                     список+:нСписок;
                                (*    стэкД+:ДкСписку;  *)
                                    данныеД :ДкПустомуНабору (* приёмник <- источник = расширению приёмника! *)
                                  );
(*
 * Цель: создать и присоединить новое (N+1)-е <звеноД> в начало стэка <список+> по <слеД>
 *                                    а в поле звена <телоД+>  заслать <данныеД>
//
//       LIFO           N+1 -> N -> ... -> 2 -> 1 -> ПУСТО
//             ВхВых <=> начЗвенД
 *)
ПЕР
          звено:ДкЗвену_телоД;
УКАЗ
  СОЗДАТЬ(звено);
          звено.телоД:=данныеД;
  ЕСЛИ
       список.начЗвенД = ПУСТО
  ТО                                 (* стэк ещё пуст - выставляем начЗвенД на 1-е звено *)
          звено.слеД
                      := ПУСТО;       (* 1 -> ПУСТО *)

       список.начЗвенД     :=звено;
                          (* звено.слеД    =  ПУСТО *)
   (*  список.начЗвенД.слеД:=ПУСТО; *)(* 1 -> ПУСТО *)

  ИНАЧЕ                              (* добавляем не 1-е звено - выставляем начЗвенД на новое (N+1)-е звено *)
 (*
                    при добавлении не нач.(1-го) звена, а только при удалении 1-го и единственного
  *)
                 звено.слеД:=список.начЗвенД; (*        N-е *) (* старая голова следует за новой головой (=новому звену)  N+1 -> N *)
                                              (* N+1 -> N   *)
       список.начЗвенД     :=звено;           (* N+1        *) (* новое звено стало головным - первым *)
    (* список.начЗвенД.слеД:= N-е; *)         (* N+1 -> N   *)
  КОН;
  УВЕЛИЧИТЬ(список.всехЗвен)

КОН ДобавитьНовЗвеноВначСписка;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА                                                                       (* (СтэкСлеД.нСписок) *)
       ДкNмуЗвену-(список+:нСписок):ДкЗвену_телоД;
(*
   Цель:  получить доступ к последнему добавленному (N-му) звену списка для обхода всех его звеньев по <слеД>
//                                           (без удаления звена)
//
//       LIFO                  N -> ... -> 2 -> 1 -> ПУСТО
//              ВхВых <=> начЗвенД
 *)
УКАЗ
           ВОЗВРАТ список.начЗвенД    (* для обхода стэка по ссылке <слеД> в звене *)
        (* ВОЗВРАТ стэкД.начЗвенД *)
КОН ДкNмуЗвену;

КОН СтэкСлеД.
