# NLP EXAM FULL PROGRAM
# Complete implementation with all functions

import nltk
import seaborn as sns
import matplotlib.pyplot as plt
from nltk.tokenize import word_tokenize, sent_tokenize, TweetTokenizer, MWETokenizer
from nltk.corpus import stopwords, wordnet
from nltk.util import ngrams
from collections import Counter
from nltk.wsd import lesk
from nltk.stem import WordNetLemmatizer, PorterStemmer
from nltk import pos_tag, ne_chunk
from textblob import TextBlob
from gensim.models import Word2Vec

# -----------------------------
# DOWNLOAD REQUIRED NLTK DATA
# -----------------------------
def download_nltk_resources():
    """Download only required NLTK data"""
    for resource in [
        'punkt', 'stopwords', 'wordnet',
        'averaged_perceptron_tagger', 'maxent_ne_chunker',
        'words', 'omw-1.4'
    ]:
        try:
            nltk.download(resource, quiet=True)
        except:
            print(f"Failed to download {resource}")

# -----------------------------
# 1. TOKENIZATION
# -----------------------------
def tokenization_demo(text="Hello World - NLP Exam"):
    """Demonstrate different tokenization methods"""
    print("\n=== TOKENIZATION ===" )
    
    token1 = word_tokenize(text)
    token2 = sent_tokenize(text)
    token3 = TweetTokenizer().tokenize(text)
    token4 = MWETokenizer().tokenize(word_tokenize(text))
    
    print("Word Tokenize:", token1)
    print("Sentence Tokenize:", token2)
    print("Tweet Tokenize:", token3)
    print("MWE Tokenize:", token4)
    
    return token1

# -----------------------------
# 2. STOPWORD REMOVAL
# -----------------------------
def stopword_removal_demo(tokens):
    """Remove stopwords and visualize"""
    print("\n=== STOPWORD REMOVAL ===" )
    
    stop = stopwords.words("english")
    filtered_tokens = [i for i in tokens if i.lower() not in stop]
    
    print("Before:", tokens)
    print("After Stopword Removal:", filtered_tokens)
    
    # Visualization
    x1 = ["Before", "After"]
    y1 = [len(tokens), len(filtered_tokens)]
    
    plt.figure(figsize=(8, 5))
    sns.barplot(x=x1, y=y1, color="red")
    plt.title("Stopword Removal Effect")
    plt.ylabel("Token Count")
    plt.show()
    
    return filtered_tokens

# -----------------------------
# 3. WORDNET
# -----------------------------
def wordnet_demo(word="good"):
    """Extract synonyms, antonyms, and hypernyms"""
    print("\n=== WORDNET ===" )
    
    synonyms, antonyms, hypernyms = set(), set(), set()
    
    for syn in wordnet.synsets(word):
        for lemma in syn.lemmas():
            synonyms.add(lemma.name())
            if lemma.antonyms():
                antonyms.add(lemma.antonyms()[0].name())
        for hyper in syn.hypernyms():
            hypernyms.add(hyper.lemmas()[0].name())
    
    print(f"Word: {word}")
    print("Synonyms:", synonyms)
    print("Antonyms:", antonyms)
    print("Hypernyms:", hypernyms)
    
    return synonyms, antonyms, hypernyms

# -----------------------------
# 4. N-GRAMS & LAPLACE SMOOTHING
# -----------------------------
def ngrams_laplace_demo(sentence="The government plans to increase spending on education."):
    """Calculate n-grams and Laplace smoothing probability"""
    print("\n=== N-GRAMS & LAPLACE SMOOTHING ===" )
    
    tokens = word_tokenize(sentence)
    unigram = list(ngrams(tokens, 1))
    bigram = list(ngrams(tokens, 2))
    
    unigram_counter = Counter(unigram)
    bigram_counter = Counter(bigram)
    vocab_size = len(set(tokens))
    
    # Calculate Laplace probability for "to increase"
    count_to_increase = bigram_counter[("to", "increase")]
    count_to = unigram_counter[("to",)]
    
    prob = (count_to_increase + 1) / (count_to[0] + vocab_size) if count_to else 1 / vocab_size
    
    print("Unigrams:", unigram)
    print("Bigrams:", bigram)
    print(f"Laplace Probability (to → increase): {prob:.4f}")
    
    return prob

# -----------------------------
# 5. LESK WORD SENSE DISAMBIGUATION
# -----------------------------
def lesk_demo(tokens, target_word="World"):
    """Perform LESK word sense disambiguation"""
    print("\n=== LESK WORD SENSE DISAMBIGUATION ===" )
    
    sense = lesk(tokens, target_word)
    
    if sense:
        print(f"LESK Sense for '{target_word}':", sense.definition())
    else:
        print(f"LESK: No sense found for '{target_word}'")
    
    return sense

# -----------------------------
# 6. LEMMATIZATION & STEMMING
# -----------------------------
def lemmatization_stemming_demo(tokens):
    """Compare lemmatization and stemming"""
    print("\n=== LEMMATIZATION & STEMMING ===" )
    
    lemmatizer = WordNetLemmatizer()
    stemmer = PorterStemmer()
    
    results = []
    for token in tokens:
        lemma = lemmatizer.lemmatize(token.lower())
        stem = stemmer.stem(token.lower())
        results.append((token, lemma, stem))
        print(f"{token} → Lemma: {lemma}, Stem: {stem}")
    
    return results

# -----------------------------
# 7. POS TAGGING & NER
# -----------------------------
def pos_ner_demo(tokens):
    """Perform POS tagging and Named Entity Recognition"""
    print("\n=== POS TAGGING & NER ===" )
    
    tags = pos_tag(tokens)
    ner = ne_chunk(tags)
    
    print("POS Tags:", tags)
    print("NER Tree:", ner)
    
    return tags, ner

# -----------------------------
# 8. SENTIMENT ANALYSIS
# -----------------------------
def sentiment_analysis_demo(text="It was a bad day"):
    """Analyze sentiment polarity and subjectivity"""
    print("\n=== SENTIMENT ANALYSIS ===" )
    
    blob = TextBlob(text)
    polarity = blob.sentiment.polarity
    subjectivity = blob.sentiment.subjectivity
    
    print(f"Text: {text}")
    print(f"Sentiment Polarity: {polarity}")
    print(f"Sentiment Subjectivity: {subjectivity}")
    
    if polarity > 0:
        print("Sentiment: Positive")
    elif polarity < 0:
        print("Sentiment: Negative")
    else:
        print("Sentiment: Neutral")
    
    return polarity, subjectivity

# -----------------------------
# 9. WORD2VEC
# -----------------------------
def word2vec_demo(sentences=None):
    """Train Word2Vec model and visualize similarity"""
    print("\n=== WORD2VEC ===" )
    
    if sentences is None:
        sentences = [word_tokenize("NLP is part of machine learning")]
    
    model = Word2Vec(sentences, min_count=1, vector_size=100, window=5)
    
    # Get most similar words
    try:
        target_word = sentences[0][0]  # First word in first sentence
        similar_words = model.wv.most_similar(target_word, topn=5)
        words, scores = zip(*similar_words)
        
        print(f"Most similar words to '{target_word}':")
        for word, score in similar_words:
            print(f"  {word}: {score:.4f}")
        
        # Visualization
        plt.figure(figsize=(10, 6))
        sns.barplot(x=list(words), y=list(scores))
        plt.ylabel(f"Similarity to '{target_word}'")
        plt.title("Word2Vec Similarity")
        plt.xticks(rotation=45)
        plt.tight_layout()
        plt.show()
        
    except Exception as e:
        print(f"Could not visualize: {e}")
    
    return model

# -----------------------------
# MAIN FUNCTION - RUN ALL
# -----------------------------
def run_all_nlp_functions():
    """Execute all NLP functions in sequence"""
    print("\n" + "="*50)
    print("NLP EXAM FULL PROGRAM")
    print("="*50)
    
    # Download resources
    download_nltk_resources()
    
    # 1. Tokenization
    tokens = tokenization_demo()
    
    # 2. Stopword Removal
    filtered_tokens = stopword_removal_demo(tokens)
    
    # 3. WordNet
    wordnet_demo("good")
    
    # 4. N-grams & Laplace
    ngrams_laplace_demo()
    
    # 5. LESK
    lesk_demo(tokens, "World")
    
    # 6. Lemmatization & Stemming
    lemmatization_stemming_demo(tokens)
    
    # 7. POS & NER
    pos_ner_demo(tokens)
    
    # 8. Sentiment Analysis
    sentiment_analysis_demo("It was a bad day")
    
    # 9. Word2Vec
    word2vec_demo()
    
    print("\n" + "="*50)
    print("ALL FUNCTIONS COMPLETED!")
    print("="*50)

# -----------------------------
# EXAMPLE USAGE
# -----------------------------
if __name__ == "__main__":
    run_all_nlp_functions()
