// Chattr - Twitter client on .NET
//
// Copyright (c) 2007 Katsuhiko Ichinose <ichi@users.sourceforge.jp>
//
// Chattr is Free Software released under GNU General Public License.
//
// $Id: twitte.rb 61 2007-07-17 18:11:25Z ichi $

using System;
using System.Collections.Generic;
using System.Text;

using System.Collections;
using System.Text.RegularExpressions;

namespace Chattr
{
    class StatusParser
    {
        private const string REGEX_USER_NAME = @"^(@)([0-9A-Za-z_]+)(.*)$";
        private const string REGEX_USER_CONT = @"^(.*?[^0-9A-Za-z_]@)([0-9A-Za-z_]+)(.*)$";

        private LinkedList<string> m_Users = new LinkedList<string>();
        private LinkedList<string> m_URLs = new LinkedList<string>();
        private LinkedList<string> m_Hashs = new LinkedList<string>();
        private LinkedList<string> m_Locations = new LinkedList<string>();

        public StatusParser(string status)
        {
            string jpn = @"℀-➾　-㏾一-龥豈-鶴！-￬";
            string anc = @"0-9a-zA-Z\-_\.!~\*'\(\)/\?&=,:%@";
            string lst = @"0-9a-zA-Z\-_\.!~\*'/";
            Regex rHttp = new Regex(@"^(.*?)((?:http|https)://[" + jpn + anc + "]*[" + lst + "])(.*)$");
            Regex rLoc = new Regex(@"^(.*?)(?:L|l):([^ ]+)(.*)$");
            Regex rUserName = new Regex(REGEX_USER_NAME);
            Regex rUserCont = new Regex(REGEX_USER_CONT);
            foreach (string text in status.Split('\n'))
            {
                string txt = text;
                while (txt != "")
                {
                    Match m = rHttp.Match(txt);
                    if (m.Success)
                    {
                        ParseUserName(m.Groups[1].Value);
                        ParseHash(m.Groups[1].Value);
                        AddURL(m.Groups[2].Value);
                        txt = m.Groups[3].Value;
                    }
                    else
                    {
                        m = rLoc.Match(txt);
                        if (m.Success)
                        {
                            ParseUserName(m.Groups[1].Value);
                            ParseHash(m.Groups[1].Value);
                            AddLocation(m.Groups[2].Value);
                            txt = m.Groups[3].Value;
                        }
                        else
                        {
                            ParseUserName(txt);
                            ParseHash(txt);
                            txt = "";
                        }
                    }
                }
            }
        }

        private void ParseUserName(string status)
        {
            Regex rUserName = new Regex(REGEX_USER_NAME);
            Regex rUserCont = new Regex(REGEX_USER_CONT);
            Match mUserName = rUserName.Match(status);
            Match mUserCont = rUserCont.Match(status);
            while (mUserName.Success || mUserCont.Success)
            {
                if (mUserName.Success)
                {
                    AddUser(mUserName.Groups[2].Value);
                    status = mUserName.Groups[3].Value;
                }
                else if (mUserCont.Success)
                {
                    AddUser(mUserCont.Groups[2].Value);
                    status = mUserCont.Groups[3].Value;
                }
                mUserName = rUserName.Match(status);
                mUserCont = rUserCont.Match(status);
            }
        }

        private void ParseHash(string status)
        {
            Regex rHash = new Regex(@"^(.*?)(\#[\!-\~]+)(.*)$");
            Match mHash = rHash.Match(status);
            while (mHash.Success)
            {
                if (mHash.Success)
                {
                    AddHash(mHash.Groups[2].Value);
                    status = mHash.Groups[3].Value;
                }
                mHash = rHash.Match(status);
            }
        }

        private void AddUser(string user)
        {
            m_Users.AddLast(user);
        }

        private void AddURL(string url)
        {
            m_URLs.AddLast(url);
        }

        private void AddHash(string hash)
        {
            m_Hashs.AddLast(hash);
        }

        private void AddLocation(string location)
        {
            m_Locations.AddLast(location);
        }

        public LinkedList<string> Users
        {
            get
            {
                return m_Users;
            }
        }

        public LinkedList<string> URLs
        {
            get
            {
                return m_URLs;
            }
        }

        public LinkedList<string> Hashs
        {
            get
            {
                return m_Hashs;
            }
        }

        public LinkedList<string> Locations
        {
            get
            {
                return m_Locations;
            }
        }
    }
}
