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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

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

КОН СтэкПреД.
