typedef map<string,int,less<string> >  tarfn;

   static tarfn arfn;


   class CodeObject
   {
   public:
      CodeObject(BOOL ignorecase);
      ~CodeObject();
      long LoadFromFile(char *filename);
      void PrintToLog(ofstream *f);
      long MyCode(char *s);
      long FindClose(char *s);
      int Crel(char *s);
      int Cfstd(char *s);
      int Cocc(char *, int skip);
      int Cyrke(char *, int skip);
      void PrintUkoda (ofstream *f,long persons, char t, int terskel);
      void InsertUkoda(char *s);
      char *GetWord(char *s);
      int KodeOrd(char *s);
      int aar;
   protected:
      tarfn::iterator lti;
      long notcoded;
      Setning Setn;
   private:
      int kode;
      int manglar;
      long numcodes;
      tarfn codetab;
      char buff[256], buf2[256];
      tarfn ukoda;
      BOOL caseignore;
      void lowcase(char *line);
      int CharOK(char c);

   };

CodeObject::CodeObject(BOOL ignorecase)
{
    manglar=9999;
    caseignore=ignorecase;
}

CodeObject::~CodeObject()
{
    codetab.clear();
}

void CodeObject::lowcase(char *line)
{
        char *s;
//        int tal;

        s=line;
        while (*line!=NULL) {
          if ((*line>'_' && *line<'{') || (*line==' ')) ;
          else
          if (*line>'@' && *line<'[')
              *line=(int) *line + 32;
          else {
//             tal=(int) *line;
             switch ((int) *line) {
             case 197, -59 : *line=229; break;// Ansi Å-å
             case 198, -58 : *line=230; break;// Ansi Æ-æ
             case 216, -40 : *line=248; break;// Ansi Ø-ø
             case 145, -113 : *line=230; break;// DOS æ Ansi æ
             case 134, -122 : *line=229;break; // DOS å Ansi å
             case 146, -111 : *line=230; break;// DOS Æ ansi æ
             case 143, -114 : *line=229; break;// DOS Å ansi å
             case 155, -101 : *line=248; break;// DOS ø ansi ø
             case 157, -99 : *line=248;break; // DOS Ø ansi ø;
             case 44  : *line=32; break;// , til <blank>
             }
           }
         line++;
        }
        line=s;
}


   long CodeObject::LoadFromFile(char *fn)
   {
      FILE *fp;
      char line[256];
      char *s, *kode;
      long i,codenum;

      manglar=9999;
      fp=fopen(fn,"r");
      i=0;
      if (fp!=NULL) {
         while (fgets(line,255,fp)!=NULL) {
            s=strchr(line,';');
            if (s==NULL) s=strchr(line,'\t');
            if (s!=NULL) {
               kode=s;
               kode++;
               *s='\0';
               codenum=atol(kode);
            }
            else
               codenum=9999;
            if (caseignore==TRUE)
                lowcase(line);
            if (codenum<1 || codenum>9999) codenum=9999;
            else codetab[line]=codenum;
            i++;
         }
         fclose(fp);
      }
      numcodes=i;
      printf("Numcodes read: %d\t%d\t",numcodes,codetab.size());
      return numcodes;
   }

   long CodeObject::MyCode(char *s)
   {
      if (caseignore==TRUE)
         lowcase(s);
      lti=codetab.find(s);
      if (lti!=codetab.end()) {
         manglar=(*lti).second;
      }
      else
         manglar=9999;
      return manglar;
   };

   void CodeObject::InsertUkoda(char *s)
   {
         ukoda[string(s)]++;
   }

   char *CodeObject::GetWord(char *s)
   {
      char *p, *f;

      if (s[0]=='\0') return '\0';
      f=s;
      p=strchr(s, ' ');
      if (p!=NULL) {
          s=p;
          s++;
          *p='\0';
      }
      else {*f='\0';}
      return f;
   }


   int  CodeObject::KodeOrd(char *s)
   {
        int kode;
        if (*s=='\0') return -1;
        kode=MyCode(s);
        if (kode<9999) {
           *s='\0';
           return kode;
        }
        else {
           s=GetWord(s);
           kode=MyCode(s);
        }
        return kode;
   }

   long CodeObject::FindClose(char *s)
   {
      lti=codetab.lower_bound(s);
      if (lti!=codetab.end()) {
         manglar=(*lti).second;
      //         cout << (*lti).first << ";" << s << endl;
      }
      else
         manglar=9999;
      return manglar;
   };

void CodeObject::PrintToLog (ofstream *f)
{
 for (lti=codetab.begin();lti!=codetab.end();lti++) {
   *f << (*lti).first << "\t" << (*lti).second << endl;
 }
}

void CodeObject::PrintUkoda (ofstream *f,long persons, char t, int terskel)
{
  for (lti=ukoda.begin();lti!=ukoda.end();lti++) {
    if ((*lti).second>terskel)
       *f << t << "\t" << (*lti).first << "\t" << (*lti).second << endl;
    notcoded+=(long) (*lti).second;
  }
  *f << t << "\t" << notcoded << "\t" << persons << endl;
}
   int CodeObject::CharOK(char c)
   {
   switch (c) {
   case '\'': return 0;
   case '.': return 0;
   case ')': return 0;
   case '(': return 0;
   case '?': return 0;
   case '=': return 0;
   case '-': return 0;
   }
   return c;
   };
   int CodeObject::Crel(char *s)
   {
      char *p, *f;
      int i,j;
      if (s[0]=='\0') return 9999;
      p=strchr(s, '%');
      if (p && p>&s[0]) {
// Fjernar alt etter %% dvs. overstryking
         p--;
         while ((*p==' ' || *p=='(') && (p>&s[0])) --p;
         if (++p>&s[0]) *p='\0';
      }
      if (s[strlen(s)-1]=='.')
// Fjernar avsluttande punktum
         s[strlen(s)-1]='\0';
      if (strlen(s)<3 && aar==1900) {
         switch (toupper(s[0])) {
            case 'S':
               return 31;
            case 'D':
               return 32;
            case 'B':
               return BESOK;
            case 'H':
               if (toupper(s[1])=='F')
                  return 11;
               else if (toupper(s[1])=='M')
                  return 22;
            case 'E':
               if (toupper(s[1])=='L')
                  return EL;
            case 'F':
               if (toupper(s[1])=='L')
                  return FL;
            case 'T':
               return SERV;
            case '!':
                 if (s [1]=='!')
                    return 9999;
            case '\0': case '?':
               return 9999;
         }
      }
      else {
        kode=MyCode(s);
        if (kode>=10 && kode<9999)
          return kode;
      }
      j=0;
      for (i=0;(i<strlen(s)) && (i<256);i++) {
         if (CharOK(s[i])==0) {
            if ((CharOK(s[i+1])!=32) && (i>0)
             && (CharOK(s[i-1])!=32) && (s[i]!='\'')
             && (s[i]!='-')) {
               if (buff[j-1]!=' ') {
                 buff[j]=' ';
                 j++;
               }
            }
         }
         else
             buff[j++]=s[i];
      };
      buff[j]='\0';
      if (buff[j-1]==' ') buff[j-1]='\0';
      buf2[0]=buff[0];
      j=1;
      for (i=1;i<strlen(buff);i++)
         if (buff[i]==' ' && buff[i-1]==' ')
         kode=0;
         else buf2[j++]=buff[i];
      buf2[j]='\0';
      strcpy(buff,buf2);
      kode=MyCode(buff);
      if (kode>=10 && kode<9999)
         return kode;
//      strcpy(buff,s);
      p=strrchr(buff,' ');
      f=strchr(buff,' ');
      if (f<=p) {
         if (f-&buff[0]==3) {
         lowcase(buff);
          if ((strncmp(buff,"hfs",3)==0)
          || (strncmp(buff,"hms",3)==0)) {
            f++;
            kode=MyCode(f);
            if (kode>=0 && kode<9999)
               return kode;
          }
         }
         else if (f-&buff[0]==5) {
          lowcase(buff);
          if (strncmp(buff,"deres",5)==0) {
            f++;
            kode=MyCode(f);
            if (kode>=0 && kode<9999)
               return kode;
          }
         }
      }
      while (p) {
         *p='\0';
/*         if (aar==1900)
           kode=this->Crel(&buff[0]);
         else*/
         p--;
         while ((*p==' ' || *p=='(') && (p>&buff[0]))
             --p;
         if (++p>&buff[0]) *p='\0';
         kode=MyCode(buff);
         if (kode>=10 && kode<9999)
            return kode;
         p=strrchr(buff,' ');
      };
/*      kode=FindClose(s);
      if (kode>=10 && kode<9999)
         return kode;  */
      ukoda[string(s)]++;
      return 9999;
   }

   int CodeObject::Cfstd(char *s)
   {
      char *p;
      if ((*s=='t' || *s=='T') && (*(s+1)=='\0'))
         return 1;
      else if (*s== '\0')
         return 1;
      kode=MyCode(s);
      if (kode>100 && kode<7001)
         return kode;
      strcpy(buff,s);
      p=strchr(buff,' ');
      if (p) {
         Setn.SetData(buff);
         kode=MyCode(Setn.GetLast());
         if (kode>100 && kode<7001)
            return kode;
         *p='\0';
         kode=MyCode(buff);
         if (kode>100 && kode<7001)
            return kode;
      };
      strcpy(buff,s);
      p=strrchr(buff,' ');
      while (p) {
         *p='\0';
         p--;
         while ((*p==' ' || *p=='(') && (p>&buff[0]))
             --p;
         if (++p>&buff[0]) *p='\0';
         kode=MyCode(buff);
         if (kode>100 && kode<7001)
            return kode;
         p=strrchr(buff,' ');
      };
/*      if (strlen(buff)>4)  buff[strlen(buff)-1]='\0';
      kode=FindClose(buff);
      if (kode>100 && kode<7001)

        return kode;*/
      ukoda[string(buff)]++;
      ukoda[string(s)]++;
      return 9999;
   }

   int CodeObject::Cocc(char *s, int head)
   {
      if (s[0]=='\0')
         return 9999;
      kode=MyCode(s);
      if (kode>0 && kode<9999)
         return kode;
      if (head==1)
         ukoda[string(s)]++;
      return 9999;
   }

   int CodeObject::Cyrke(char *s, int head)
   {
      char *p;

      if (s[0]=='\0')
         return 9999;
      kode=MyCode(s);
      if (kode>0 && kode<9999)
         return kode;
      strcpy(buff,s);
      p=strrchr(buff,' ');
      while (p) {
        *p='\0';
         p--;
         while ((*p==' ' || *p=='(' || *p=='.' || *p==')') && (p>&buff[0]))
             --p;
         if (++p>&buff[0]) *p='\0';
         kode=MyCode(buff);
         if (kode>=10 && kode<9999)
            return kode;
         p=strrchr(buff,' ');
      };
      if (head==1)
         ukoda[string(s)]++;
      return 9999;
   }