<!--
/*-------------------------------------------------------------------------------------------------*/
/* Sortti.js                                                                                       */
/*-------------------------------------------------------------------------------------------------*/
/* Näyttää HTML-sivun taulukon lajiteltuna halutun sarakkeen mukaiseen järjestykseen.              */
/* Taulukon kaikilla riveillä täytyy olla sama määrä sarakkeita (soluja)¨.                         */
/* Ensimmäisen rivin solut käsitellään sarakkeiden otsikoina.                                      */
/* Lajiteltava sarake määritellään napsauttamalla otsikkosolua.                                    */
/* Normaalisti lajittelujärjestys on nouseva, mutta napsauttamalla samaa solua toistuvasti         */
/* peräkkäin, vaihtuu järjestys joka kerta käänteiseksi.                                           */
/* Laiteltu sarake ja suunta ilmoitetaan tilarivillä.                                              */
/*-------------------------------------------------------------------------------------------------*/
/* Seuraava tyylimäärittely HTML-tiedoston <HEAD> -osassa:                                         */
/* - estää kursorin muuttumisen tekstikursoriksi (pystyviiva)                                      */
/* - asettaa <TH>-koodilla määriteltyjen otsikkosolujen taustavärin harmaaksi                      */
/* - asettaa kursorin <TH>-koodilla määriteltyjen otsikkosolujen päällä sormeksi                   */
/* - estää tekstin rivittymisen soluissa                                                           */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*    <STYLE>                                                                                      */
/*       BODY        {  cursor:default;                        }                                   */
/*       TH          {  background-color:#EEEEEE;cursor:hand;  }                                   */
/*       TD          {  white-space:nowrap;                    }                                   */
/*    </STYLE>                                                                                     */
/*-------------------------------------------------------------------------------------------------*/
/* Lisää HTML-tiedoston <HEAD> -osaan scriptin määrittely:                                         */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*    <SCRIPT LANGUAGE="JavaScript" SRC="Sortti.js"></SCRIPT>                                      */
/*-------------------------------------------------------------------------------------------------*/
/* Voit määritellä taulukon ensimmäisen rivin solut <TH> -koodeilla otsikkosoluiksi, jos haluat    */
/* käyttää edellä mainittuja tyylimuotoiluja. Jollet halua käyttää tyyliä, jätä <STYLE> -osa pois  */
/* ja määrittele solut normaalisti <TD> -koodeilla.                                                */
/* Määrittele ensimmäisen rivin soluihin onClick="Sorttaa(this,'TYYPPI');" -lajittelukutsut:       */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*    <TABLE>                                                                                      */
/*       <TR>                                                                                      */
/*          <TH onClick="Sorttaa(this,'TYYPPI');"> Sarakeotsikko 1 </TH>                           */
/*          <TH onClick="Sorttaa(this,'TYYPPI');"> Sarakeotsikko 2 </TH>                           */
/*          ...                                                                                    */
/*       </TR>                                                                                     */
/*       <TR>                                                                                      */
/*          <TD> Data </TD>                                                                        */
/*          <TD> Data </TD>                                                                        */
/*          ...                                                                                    */
/*       </TR>                                                                                     */
/*       ...                                                                                       */
/*    </TABLE>                                                                                     */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Parametrit:                                                                                     */
/*    this        Viittaa automaattisesti kyseiseen sarakkeeseen. (Huom! pienillä kirjaimilla)     */
/*    'TYYPPI'    Lajiteltavan tiedon tyyppi. (Huom! Lainausmerkit)                                */
/*                Tyypit on kuvattu Muunna -funktion yhteydessä.                                   */
/*-------------------------------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------------------------------*/
/* Sivun latauksessa tehtävät alustustoimet                                                        */
/*-------------------------------------------------------------------------------------------------*/

var Taulukko                           // Varataan pointteri taulukkoa varten
var RiviLkm, SarLkm;                   // Varataan muuttujat rivien ja sarakkeiden lukumäärille
var SortSar = -1, EdellSar = -1;       // Alustetaan muuttujat lajiteltavan sarakkeen numeroille
var Nouseva = false;                   // Alustetaan ensimmäisen lajittelun suunta nousevaksi
var ApuTaulukko = null;                // Alustetaan datan aputaulukon muuttuja tyhjäksi (null)
var SortTaulukko = null;               // Alustetaan lajittelun aputaulukon muuttuja tyhjäksi (null)
var OK = true, Peru = false;           // Paluukoodit

function Sorttaa(Solu,Tyyppi)
/*-------------------------------------------------------------------------------------------------*/
/* "Pääohjelma", joka käynnistää eri "aliohjelmat".                                                */
/*-------------------------------------------------------------------------------------------------*/
/* Solu     Pointteri lajiteltavaan sarakeeseen. Aina 'this' (ilman hipsuja).                      */
/* Tyyppi   Lajiteltavan tiedon tyyppi (lainausmerkeissä).                                         */
/*          Tyypit on kuvattu Muunna -funktion yhteydessä.                                         */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Tarkistaa, että kutsun muoto ja taulukon rakenne on oikea.                                      */
/* Lukee taulukon tiedot aputaulukoihin.                                                           */
/* Lajittelee aputaulukon.                                                                         */
/* Kirjoittaa lajitellut tiedot takaisin näytettävään taulukkoon.                                  */
/*-------------------------------------------------------------------------------------------------*/
{
   if (ParametritOK(arguments.length,Tyyppi))   // Tarkistaa parametrien määrän ja tyypin
   {
      if (TaulukkoOK(Solu,Tyyppi))              // Tarkistaa, että taulukon rakenne on kelvollinen
      {
         if (LueTaulukko(Tyyppi))               // Lukee tiedot taulukosta aputaulukoihin
         {
            SorttaaRivit();                     // Lajittelee aputaulukon rivit
            KirjoitaTaulukko();                 // Tulostaa tiedot aputaulukosta näytettävään taulukkoon
         }
      }
   }
}

function ParametritOK(ParamLkm,Tyyppi)
/*-------------------------------------------------------------------------------------------------*/
/* Tarkistaa HTML-sivun kutsun parametrit.                                                         */
/*-------------------------------------------------------------------------------------------------*/
/* ParamLkm    Parametrien lukumäärä.                                                              */
/* Tyyppi      Lajiteltavan tiedon tyyppi.                                                         */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Tarkistaa, että parametreja on oikea määrä ja Tyyppi on kelvollinen.                            */
/* Palauttaa 'OK' tai 'Peru'.                                                                      */
/*-------------------------------------------------------------------------------------------------*/
{
   if (ParamLkm != 2)                           // Jos parametrien lukumäärä ei ole 2 ...
      return(Virhe("PARAM_LKM",ParamLkm));      // ... virheilmoitus ja epäonnistumisen paluukoodi

   if ("|TXT|KIR|NUM|PVM|PKV|VKP|KPV|".indexOf("|" + Tyyppi.toUpperCase() + "|") < 0)  // Jos Tyyppi ei ole kelvollinen ...
      return(Virhe("PARAM_TYYPPI",Tyyppi));     // ... virheilmoitus ja epäonnistumisen paluukoodi

   return(OK);                                  // Onnistumisen paluukoodi
}

function TaulukkoOK(Solu,Tyyppi)
/*-------------------------------------------------------------------------------------------------*/
/* Tarkistaa taulukon rakenteen.                                                                   */
/*-------------------------------------------------------------------------------------------------*/
/* Solu     Pointteri lajiteltavaan sarakkeeseen.                                                  */
/* Tyyppi   Lajiteltavan tiedon tyyppi.                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Selvittää lajiteltavan sarakkeen numeron.                                                       */
/* Jos taulukko on tarkistettu aikaisemmin, palauttaa 'OK'.                                        */
/* Tarkistaa taulukon rakenteen. Jos se ei ole kelvollinen, palauttaa 'Peru'.                      */
/* Muodostaa tyhjät aputaulukot ja palauttaa 'OK'.                                                 */
/*-------------------------------------------------------------------------------------------------*/
{
   status = "Taulukon rakenteen tarkistus...";                       // Tilariville tieto tarkistuksen aloituksesta

   SortSar = Solu.cellIndex;                                         // Lajiteltavan sarakkeen numero.

   if ((ApuTaulukko != null) && (SortTaulukko != null))              // Jos aputaulukot on muodostettu, taulukko on jo tarkistettu
   {
      status = "Taulukon rakenne on hyväksytty jo aikaisemmin!";     // Tilariville tieto aikaisemmasta tarkistuksesta
      return(OK);                                                    // Onnistumisen paluukoodi
   }

   Taulukko = Solu.parentElement.parentElement.parentElement;        // Pointteri taulukon alkuun
   TaulukkoTyyppi = Taulukko.tagName;                                // Taulukon tyyppi
   if (TaulukkoTyyppi != "TABLE")                                    // Jos ei ole taulukko ...
   {
      return(Virhe("TABLE"));                                        // ... virheilmoitus ja epäonnistumisen paluukoodi
   }

   RiviLkm = Taulukko.rows.length;                                   // Taulukon rivien määrä
   if (RiviLkm <= 2)                                                  // Jos rivejä on korkeintaan 2 ...
   {
      return(Virhe("RIVI_LKM",RiviLkm));                             // ... virheilmoitus ja epäonnistumisen paluukoodi
   }

   SarLkm = Taulukko.rows[0].cells.length;                           // Otsikkorivin sarakkeiden määrä

   ApuTaulukko = new Array(RiviLkm);                                 // Datan aputaulukon rivit
   SortTaulukko = new Array(RiviLkm);                                // Lajittelun aputaulukon rivit

   for (RiviNum = 0; RiviNum < RiviLkm; RiviNum++)
   {
      ApuTaulukko[RiviNum] = new Array(SarLkm);                      // Datan aputaulukon sarakkeet
      SortTaulukko[RiviNum] = new Array(2);                          // Lajittelun aputaulukon sarakkeet
   }

   status = "Taulukon rakenne OK! (" + RiviLkm + " riviä; " + SarLkm + " saraketta)";  // Tilariville tieto tarkistuksen onnistumisesta
   return(OK);                                                       // Onnistumisen paluukoodi
}

function LueTaulukko(Tyyppi)
/*-------------------------------------------------------------------------------------------------*/
/* Tietojen luku taulukosta aputaulukoihin.                                                        */
/*-------------------------------------------------------------------------------------------------*/
/* Tyyppi   Lajiteltavan tiedon tyyppi.                                                            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Lukee taulukon riveittäin.                                                                      */
/* Jos rivin sarakkeiden (solujen) määrä poikkeaa otsikkorivistä, palauttaa 'Peru'.                */
/* Tallettaa solujen sisällöt HTML-koodeineen datan aputaulukkoon.                                 */
/* Tallettaa rivinumerot ja lajiteltavan sarakkeen solut "siivottuina" ja tyypin mukaan            */
/* muunnettuina lajittelun aputaulukkoon.                                                          */
/* Palauttaa 'OK'.                                                                                 */
/*-------------------------------------------------------------------------------------------------*/
{
   status = "Tietojen luku taulukosta...";            // Tilariville tieto lukemisen aloituksesta

   for (RiviNum = 0; RiviNum < RiviLkm; RiviNum++)
   {
      status = "Tietojen luku taulukosta... (Rivi: " + RiviNum + ")";   // Tilariville tieto luettavasta rivistä

      SarKpl = Taulukko.rows[RiviNum].cells.length;   // Rivin sarakkeiden määrä

      if (SarKpl != SarLkm)                           // Jos sarakkeiden määrä ei vastaa otsikkoriviä ...
      {
         return(Virhe("SAR_LKM",RiviNum,SarKpl));     // ... virheilmoitus ja epäonnistumisen paluukoodi
      }

      for (SarNum = 0; SarNum < SarLkm; SarNum++)
      {
         ApuTaulukko[RiviNum][SarNum] = Taulukko.rows[RiviNum].cells[SarNum].innerHTML;            // Solun tiedot HTML-muotoiluineen datan aputaulukkoon
      }
      SortTaulukko[RiviNum][0] = RiviNum;                                                          // Rivinumero lajittelun aputaulukkoon
      SortTaulukko[RiviNum][1] = Muunna(Taulukko.rows[RiviNum].cells[SortSar].innerText,Tyyppi);   // Solun tiedot muunnettuina tyypin mukaiseksi lajittelun aputaulukkoon
   }
   status = "Taulukon luku OK!";                      // Tilariville tieto lukemisen onnistumisesta
   return(OK);                                        // Onnistumisen paluukoodi
}

function SorttaaRivit()
/*-------------------------------------------------------------------------------------------------*/
/* Lajittelee lajittelun aputaulukon rivit.                                                        */
/*-------------------------------------------------------------------------------------------------*/
/* Asettaa lajittelun suunnan. Jos lajiteltava sarake on sama kuin edellisellä kerralla, vaihtaa   */
/* suuntaa, muuten lajittelee nousevasti.                                                          */
/* Asettaa lajiteltavan sarakkeen numeron edelliseksi.                                             */
/* Lajittelee lajittelun aputiedoston rivit, jolloin talletetut rivinumerot ilmoittavat datan      */
/* aputiedoston rivien lajiteltavan järjestyksen.                                                  */
/*-------------------------------------------------------------------------------------------------*/
{
   var   Apu;                                            // Apumuuttuja
   var   i = 0, j = 0;

   status = "Lajittelu alkaa ...";                       // Tilariville tieto lajittelun alkamisesta

   Nouseva = (SortSar == EdellSar ? !Nouseva : true);    // Jos lajiteltavan sarakkeen numero on sama kuin edellisellä kerralla, vaihtaa suunnan päinvastaiseksi, muuten nousevaksi.
   EdellSar = SortSar;                                   // Lajiteltavan sarakkeen numero seuraavaa kertaa varten edelliseksi numeroksi.

   for (i = 1; i < RiviLkm; i++)                         // Kuplalajittelu (Bubble Sort)
   {
      status = "Lajittelu " + " (" + i + "/" + RiviLkm + ")";
      for (j = i + 1;j < RiviLkm; j++)
      {
         if ((Nouseva && (SortTaulukko[i][1] > SortTaulukko[j][1])) ||
            (!Nouseva && (SortTaulukko[i][1] < SortTaulukko[j][1])))
         {
            Apu = SortTaulukko[i][1];
            SortTaulukko[i][1] = SortTaulukko[j][1];
            SortTaulukko[j][1] = Apu;
            Apu = SortTaulukko[i][0];
            SortTaulukko[i][0] = SortTaulukko[j][0];
            SortTaulukko[j][0] = Apu;
         }
      }
   }
   status = ApuTaulukko[0][SortSar] + " (sarake " + (SortSar + 1) + ") lajiteltu " + (Nouseva ? "nousevasti" : "laskevasti");    // Tilariville tieto lajittelun loppumisesta
   return(OK);                                           // Onnistumisen paluukoodi
}

function KirjoitaTaulukko()
/*-------------------------------------------------------------------------------------------------*/
/* Tulostaa aputaulukon tiedot lajiteltuna näytettävälle taulukolle.                               */
/*-------------------------------------------------------------------------------------------------*/
/* Lukee rivinumerot lajittelun aputaulukosta ja tulostaa sen mukaan solujen sisällöt              */
/* tulostettavaan taulukkoon.                                                                      */
/*-------------------------------------------------------------------------------------------------*/
{
   status = "Lajiteltujen tietojen tulostus taulukkoon alkaa ...";   // Tilariville tieto tulostuksen alkamisesta

   for (RiviNum = 0; RiviNum < RiviLkm; RiviNum++)
   {
      status = "Tietojen tulostus (" + RiviNum + "/" + RiviLkm + ")";
      for (SarNum = 0; SarNum < SarLkm; SarNum++)
      {
         SortNum = SortTaulukko[RiviNum][0];             // Lukee datan aputaulukon rivinumeron lajittelun aputaulukosta
         Taulukko.rows[RiviNum].cells[SarNum].innerHTML = ApuTaulukko[SortNum][SarNum];   // Asettaa aputaulukon solut HTML-koodeineen tulostettavaan taulukkoon
      }
   }
   status = ApuTaulukko[0][SortSar] + " (sarake " + (SortSar + 1) + ") lajiteltu " + (Nouseva ? "nousevasti" : "laskevasti");    // Tilariville tieto lajittelun loppumisesta
   return(OK);                                           // Onnistumisen paluukoodi
}

function Muunna(Muunnettava,Tyyppi)
/*-------------------------------------------------------------------------------------------------*/
/* Muuntaa taulukon tiedon Tyypin perusteella sellaiseksi, että lajittelu menee oikein.            */
/*-------------------------------------------------------------------------------------------------*/
/* Muunnettava    Muunnettava tieto                                                                */
/* Tyyppi         Muunnettavan tiedon tyyppi.                                                      */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Palauttaa muunnetun tiedon.                                                                     */
/*-------------------------------------------------------------------------------------------------*/
{
   var Apu, Tulos;

   switch (Tyyppi.toUpperCase())
   {
      case "TXT":       // Teksti; ei erottele isoja ja pieniä kirjaimia
                        Tulos = Muunnettava.toLowerCase();
                        break;

      case "KIR":       // Isot ja pienent kirjaimet erotellaan
                        Tulos = Muunnettava;
                        break;

      case "NUM":       // Luku; poistaa välit ja vaihtaa pilkut pisteiksi ja muuntaa liukuluvuksi
                        Apu = Muunnettava.split(" ").join("");
                        Apu = Apu.split(",").join(".");
                        Tulos = ((Apu == 0) ? 0 : parseFloat(Apu));
                        break;

      case "PVM":       // Selvittää päivämäärän muodon ja kutsuu vastaavaa muunnosta:
                        //    - jos '.' erottimena, pp.kk.vvvv = PKV
                        //    - jos '-' erottimena, vvvv-kk-pp = VKP
                        //    - jos '/' erottimena, kk/pp/vvvv = KPV
                        //    - muuten valmiiksi muunnettu
                        if      (Muunnettava.lastIndexOf(".") > Muunnettava.indexOf(".")) Tulos = Muunna(Muunnettava,"PKV");
                        else if (Muunnettava.lastIndexOf("-") > Muunnettava.indexOf("-")) Tulos = Muunna(Muunnettava,"VKP");
                        else if (Muunnettava.lastIndexOf("/") > Muunnettava.indexOf("/")) Tulos = Muunna(Muunnettava,"KPV");
                        else                                                              Tulos = Muunnettava;
                        break;

      case "PKV":       // Päivämäärä; pp.kk.vvvv
                        Apu = Muunnettava.split(".");
                        Tulos = new Date(Apu[2],Apu[1]-1,Apu[0]);
                        break;

      case "VKP":       // Päivämäärä; vvvv-kk-pp
                        Apu = Muunnettava.split("-");
                        Tulos = new Date(Apu[0],Apu[1]-1,Apu[2]);
                        break;

      case "KPV":       // Päivämäärä; kk/pp/vvvv
                        Apu = Muunnettava.split("/");
                        Tulos = new Date(Apu[2],Apu[0]-1,Apu[1]);
                        break;

      default:          Virhe("PARAM_TYYPPI");
                        Tulos = Muunnettava;
                        break;
   }
   return(Tulos);
}

function Virhe(Laji,Param1,Param2)
/*-------------------------------------------------------------------------------------------------*/
/* Tulostaa lajin ja parametrien mukaan virheilmoituksen tilariville ja virheilmoitusikkunaan.     */
/* Palauttaa paluukoodina 'Peru'.                                                                  */
/*-------------------------------------------------------------------------------------------------*/
{
   var st = "";      // Tilarivin alustus
   var al = "";      // Virheilmoituksen alustus

   switch (Laji.toUpperCase())
   {
      case "PARAM_LKM":    st += "!!! Parametrien määrä (" + Param1 + ") ei ole 2 !!!";
                           al += "!!! Parametrien määrä (" + Param1 + ") ei ole 2 !!! \n\n";
                           al += "Kutsun muoto: \n\n";
                           al += "   onClick=\"Sorttaa(this,'TYYPPI');\"\n";
                           al += "jossa TYYPPI on joku seuraavista: \n";
                           al += "   TXT, KIR, NUM, PVM, PKV, VKP, KPV";
                           break;
      case "PARAM_TYYPPI": st += "!!! Parametrin tyyppi (" + Param1 + ") on väärin !!!";
                           al += "!!! Parametrin tyyppi (" + Param1 + ") on väärin !!! \n\n";
                           al += "Sallitut tyypit: \n\n";
                           al += "TXT = teksti \n";
                           al += "KIR = isot ja pienet kirjaimet \n";
                           al += "NUM = luku \n";
                           al += "PVM = päivämäärä; automaattinen muodon selvitys \n";
                           al += "PKV = päivämäärä; pp.kk.vvvv \n";
                           al += "VKP = päivämäärä; vvvv-kk-pp \n";
                           al += "KPV = päivämäärä; kk/pp/vvvv \n";
                           break;
      case "TABLE":        st += "!!! Taulukon rakenne on virheellinen !!!";
                           al += "!!! Taulukon rakenne on virheellinen !!! \n\n";
                           al += "Oikea rakenne: \n";
                           al += "   <TABLE> \n";
                           al += "      <TR> \n";
                           al += "         <TH onClick=\"Sorttaa(this,'TYYPPI');\"> Sarakeotsikko </TH> \n";
                           al += "         ... \n";
                           al += "      </TR> \n";
                           al += "      <TR> \n";
                           al += "         <TD> Data </TD> \n";
                           al += "         ... \n";
                           al += "      </TR> \n";
                           al += "      ... \n";
                           al += "   </TABLE>";
                           break;
      case "RIVI_LKM":     st += "Taulukossa on liian vähän (" + Param1 + ") rivejä!";
                           al += "Taulukossa on liian vähän (" + Param1 + ") rivejä!";
                           break;
      case "SAR_LKM":      st += "Rivillä " + Param1 + " on väärä määrä (" + Param2 + "/" + SarLkm + ") sarakkeita!";
                           al += "Rivillä " + Param1 + " on väärä määrä (" + Param2 + "/" + SarLkm + ") sarakkeita!";

   }
   status = st;      // Tilarivin tulostus
   alert(al);        // Virheilmoituksen tulostus
   return (Peru);    // Epäonnistumisen paluukoodi
}
//-->

