/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: mimetypes.cpp,v 1.10.2.6 2004/07/22 23:58:18 rggammon Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

/* This file handles the mime types page of the preferences dialog box */

#include "hxcom.h"
#include "hxwintyp.h"

#include <gtk/gtk.h>

#include <string.h>
#include <stdlib.h>

#include "hxplayer-i18n.h"

#include "mimetypes.h"

/* Mime interfaces */
#include "ihxappinfo.h"
#include "ihxappinfoenum.h"
#include "ihxmimeassocmanager.h"
#include "ihxmimeinfo.h"
#include "ihxmimeinfoenum.h"
#include "chxmimemanager.h"

/* Plugin handler */
#include "hxplugn.h"
#include "hxphand.h"

/* File format info */
#include "hxformt.h"


enum
{
    COLUMN_MIME_TYPE_ASSOCIATION = 0, // can be a mime type or database name
    COLUMN_CURRENT_APPLICATION,
    COLUMN_ASSIGN,
    COLUMN_MIME_ASSOCIATION_MANAGER,
    COLUMN_MIME_TYPE,
    NUM_COLUMNS
};

extern "C"
{
    void hpd_mime_types_assign_all_video     (GtkWidget* widget);
    void hpd_mime_types_assign_all_audio     (GtkWidget* widget);
    void hpd_mime_types_assign_all_unassigned(GtkWidget* widget);
    void hpd_mime_types_assign_all           (GtkWidget* widget);    
}

struct _HXMimeTypesDialogInfo
{
    GList* file_formats_list;
    GList* mime_association_managers_list;
    GtkTreeView* tree_view;
};

static void
mime_type_assign_toggled(GtkCellRendererToggle* /* cell */,
                         gchar*                 path_str,
                         gpointer               data)
{
    GtkTreeModel *model = (GtkTreeModel *)data;
    GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
    GtkTreeIter iter;
    GtkTreeIter parent;
    GtkTreeIter child;    
    gboolean active;

    gtk_tree_model_get_iter (model, &iter, path);
    gtk_tree_model_get (model, &iter,
                        COLUMN_ASSIGN, &active,
                        -1);    
    
    active = !active;

    gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
                        COLUMN_ASSIGN, active,
                        -1);

    if(gtk_tree_model_iter_parent(model, &parent, &iter))
    {
        /* We are child, refresh the parent checkbox
           (active if all children are set, inactive otherwise) */
        gboolean parent_active = active;
        
        if(active)
        {
            /* See if all of the other children are set */        
            if(gtk_tree_model_iter_children(model, &child, &parent))
            {
                do
                {
                    gboolean child_active;
                    gtk_tree_model_get (model, &child,
                                        COLUMN_ASSIGN, &child_active,
                                        -1);
                    if(!child_active)
                    {
                        parent_active = FALSE;
                        break;
                    }
            
                } while(gtk_tree_model_iter_next(model, &child));
            }
        }
        
        gtk_tree_store_set (GTK_TREE_STORE (model), &parent,
                            COLUMN_ASSIGN, parent_active,
                            -1);
            
    }
    else
    {
        /* We are a parent -- toggle all our children to match our state */
        parent = iter;
        
        if(gtk_tree_model_iter_children(model, &child, &parent))
        {
            do
            {
                gtk_tree_store_set (GTK_TREE_STORE (model), &child,
                                    COLUMN_ASSIGN, active,
                                    -1);

            } while(gtk_tree_model_iter_next(model, &child));
        }        
    }
    
    /* clean up */
    gtk_tree_path_free (path);    
}

void
hpd_mime_types_assign_all_video(GtkWidget* /*widget*/)
{
}

void
hpd_mime_types_assign_all_audio(GtkWidget* /*widget*/)
{
}

void
hpd_mime_types_assign_all_unassigned(GtkWidget* /*widget*/)
{
}

void
hpd_mime_types_assign_all(GtkWidget* /*widget*/)
{
}

void
hxplay_mime_types_pane_apply(HXMimeTypesDialogInfo* info)
{
    GtkTreePath* path;
    GtkTreeModel* model;
    GtkTreeIter parent;
    GtkTreeIter child;
    IHXMimeAssocManager* pMimeMgr;
    gchar* mime_type = NULL;
    gchar* current_application;
    gboolean active;
    
    model = gtk_tree_view_get_model(info->tree_view);
    path = gtk_tree_path_new_first ();

    
    if(gtk_tree_model_get_iter (model, &parent, path))
    {
        do
        {            
            if(gtk_tree_model_iter_children(model, &child, &parent))
            {
                do
                {
                    gtk_tree_model_get (model, &child,
                                        COLUMN_ASSIGN, &active,
                                        COLUMN_CURRENT_APPLICATION, &current_application,
                                        COLUMN_MIME_ASSOCIATION_MANAGER, &pMimeMgr,
                                        COLUMN_MIME_TYPE, &mime_type,
                                        -1);    
                    
                    g_return_if_fail(pMimeMgr != NULL);
                    if(active)
                    {
                        /* Assign to us */
                        if(!pMimeMgr->AppExists(APP_NAME_SHORT))
                        {
                            /* Add us to the mime database */
			    gchar* path;
			    path = hxcommon_get_rel_app_path(APP_NAME_SHORT);
			    CHXMimeManager::SetupApp(pMimeMgr,
						     APP_NAME_SHORT,
						     APP_NAME_LONG,
						     path,
						     TRUE,
						     FALSE);
			    g_free(path);
                        }

                        pMimeMgr->SetAssoc(APP_NAME_SHORT,
                                           mime_type);
                    }
                    else
                    {
                        /* If the app was assigned to us, remove the
                           association, otherwise leave it as it was */
                        if(strncmp(current_application,
                                   APP_NAME_SHORT,
                                   sizeof(APP_NAME_SHORT) - 1) == 0)
                        {
                            pMimeMgr->RemoveMime(mime_type);
                        }
                        
                    }
                } while(gtk_tree_model_iter_next(model, &child));
            }            
        } while(gtk_tree_model_iter_next(model, &parent));        
    }
    
    gtk_tree_path_free (path);    
}

static void
populate_mime_types_tree_view(HXMimeTypesDialogInfo* info)
{
    GtkTreeStore* store;
    GtkCellRenderer* text_renderer;
    GtkCellRenderer* toggle_renderer;

    GList* ff_iter;
    GList* mime_iter;

    GtkTreeIter iter, child_iter;
    GtkTreeViewColumn* column;

    IHXMimeAssocManager* pMimeAssocMgr = NULL;
    IHXFileFormatObject* pFileFormat = NULL;

    memset(&iter,       0, sizeof(iter));
    memset(&child_iter, 0, sizeof(child_iter));    

    store = gtk_tree_store_new(NUM_COLUMNS,
                               G_TYPE_STRING,
                               G_TYPE_STRING,
                               G_TYPE_BOOLEAN,
                               G_TYPE_POINTER,
                               G_TYPE_STRING);
    
    ff_iter = info->file_formats_list;
    while(ff_iter)
    {
        const char** pszMimeTypes;
        const char** pszExtensions;
        const char** pszOpenNames;

        pFileFormat = (IHXFileFormatObject*)ff_iter->data;        
        pFileFormat->GetFileFormatInfo( pszMimeTypes,
                                        pszExtensions,
                                        pszOpenNames);
        while(*pszMimeTypes)
        {
            /* Properties that show up at the top treeview level */
            gboolean bToplevelHandlerIsHxplay = TRUE;
            const char* szToplevelApp = APP_NAME_SHORT;
            
            gtk_tree_store_append (store, &iter, NULL);
            
            mime_iter = info->mime_association_managers_list;
            while(mime_iter)
            {
                gboolean bHandlerIsHxplay = FALSE;
                const char* szMimeType = *pszMimeTypes;
                const char* szAppId = NULL;
                const char* szDatabaseName;
                const char* szDatabaseDescription;
                UINT32 uDatabaseVersion;
                HX_RESULT retVal;
                
                pMimeAssocMgr = (IHXMimeAssocManager*)mime_iter->data;

                pMimeAssocMgr->GetMimeSystemInfo(szDatabaseName,
                                                 szDatabaseDescription,
                                                 uDatabaseVersion);

		// setup unknown mime types
		if (!pMimeAssocMgr->MimeExists(szMimeType))
		{
		    IHXMimeInfo* pMimeInfo = NULL;
		    if (SUCCEEDED(pMimeAssocMgr->GetMime(szMimeType,
							 pMimeInfo)))
		    {
                        gchar* icon_filename;
                        icon_filename = hxcommon_locate_file("icon.png");

			pMimeInfo->SetName(szMimeType);
			pMimeInfo->SetIcon(icon_filename);

                        g_free(icon_filename);
                        
			const char** pExt = pszExtensions;
			while (*pExt)
			{
			    pMimeInfo->AddExt(*pExt);
			    ++pExt;
			}
			HX_RELEASE(pMimeInfo);
		    }
		}

                retVal = pMimeAssocMgr->GetAssoc(szMimeType, szAppId);
                if(SUCCEEDED(retVal))
                {
                    if(!szAppId)
                    {
                        szAppId = _("unknown");
                    }
                }
                else
                {		    
                    szAppId = _("none");                    
                }

                if(strstr(szAppId, APP_NAME_SHORT))
                {
                    bHandlerIsHxplay = TRUE;
                }
                else
                {
                    bToplevelHandlerIsHxplay = FALSE;
                    szToplevelApp = szAppId;
                }
                            
                gtk_tree_store_append (store, &child_iter, &iter);
                gtk_tree_store_set(store, &child_iter,
                                   COLUMN_MIME_TYPE_ASSOCIATION, szDatabaseName,
                                   COLUMN_CURRENT_APPLICATION, szAppId,
                                   COLUMN_ASSIGN, bHandlerIsHxplay,
                                   COLUMN_MIME_ASSOCIATION_MANAGER, pMimeAssocMgr,
                                   COLUMN_MIME_TYPE, *pszMimeTypes,
                                   -1);

                mime_iter = g_list_next(mime_iter);
            }            

            gtk_tree_store_set(store, &iter,
                               COLUMN_MIME_TYPE_ASSOCIATION, *pszMimeTypes,
                               COLUMN_CURRENT_APPLICATION, szToplevelApp,
                               COLUMN_ASSIGN, bToplevelHandlerIsHxplay,
                               COLUMN_MIME_ASSOCIATION_MANAGER, NULL,
                               COLUMN_MIME_TYPE, *pszMimeTypes,
                               -1);
            pszMimeTypes++;
        }

        ff_iter = g_list_next(ff_iter);
    }
        
    /* Add the model to the view */
    gtk_tree_view_set_model(info->tree_view,
			    GTK_TREE_MODEL(store));

    /* Create columns */
    text_renderer = gtk_cell_renderer_text_new();
    toggle_renderer = gtk_cell_renderer_toggle_new();

    g_signal_connect (G_OBJECT (toggle_renderer),
                      "toggled",
                      G_CALLBACK (mime_type_assign_toggled),
                      store);

    column = gtk_tree_view_column_new_with_attributes(_("MIME Info"),
                                                      text_renderer,
                                                      "text", COLUMN_MIME_TYPE_ASSOCIATION,
                                                      NULL);
    gtk_tree_view_append_column(info->tree_view, column);
    gtk_tree_view_column_set_sort_column_id(column, COLUMN_MIME_TYPE_ASSOCIATION);


    column = gtk_tree_view_column_new_with_attributes(_("Application"),
                                                      text_renderer,
                                                      "text", COLUMN_CURRENT_APPLICATION,
                                                      NULL);
    gtk_tree_view_append_column(info->tree_view, column);
    gtk_tree_view_column_set_sort_column_id(column, COLUMN_CURRENT_APPLICATION);
    
    column = gtk_tree_view_column_new_with_attributes(_("Assign to hxplay"),
                                                      toggle_renderer,
                                                      "active", COLUMN_ASSIGN,
                                                      NULL);
    gtk_tree_view_append_column(info->tree_view, column);
    gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);    
}

void
hxplay_mime_types_pane_destroy(HXMimeTypesDialogInfo* info)
{
    IHXMimeAssocManager* pMimeAssocMgr;
    IHXFileFormatObject* pFileFormat;
    GList* ff_iter;
    GList* mime_iter;
    
    ff_iter = info->file_formats_list;
    while(ff_iter)
    {
        pFileFormat = (IHXFileFormatObject*)ff_iter->data;
        HX_RELEASE(pFileFormat);
        ff_iter = g_list_next(ff_iter);
    }

    g_list_free(info->file_formats_list);

    mime_iter = info->mime_association_managers_list;   
    while(mime_iter)
    {
        pMimeAssocMgr = (IHXMimeAssocManager*)mime_iter->data;
        HX_RELEASE(pMimeAssocMgr);
        mime_iter = g_list_next(mime_iter);
    }

    g_list_free(info->mime_association_managers_list);
}


HXMimeTypesDialogInfo*
hxplay_mime_types_pane_new(GladeXML* xml,
                           HXPlayer* player)
{
    HXMimeTypesDialogInfo *info;
    GtkWidget* tree_view;    
    GtkWidget* notebook;   

    tree_view = glade_xml_get_widget (xml, "hpd_mime_types_tree_view");
    if(tree_view == NULL)
    {
        /* No mime types pane available to hook onto */
        return NULL;
    }

    notebook = glade_xml_get_widget (xml, "hpd_mime_types_notebook");
    g_return_val_if_fail(notebook != NULL, NULL);    

    info = g_new0(HXMimeTypesDialogInfo, 1);
    info->tree_view = GTK_TREE_VIEW(tree_view);
    
    /* Get the plugin manager */
    HX_RESULT retVal;
    gboolean result;
    IUnknown* pUnk;
    IHXPlugin2Handler* pPlugin2Handler;
    IHXPluginEnumerator* pPluginEnumerator;
    IHXMimeAssocManager* pMimeAssocMgr;
    IHXFileFormatObject* pFileFormat;

    result = hx_player_get_unknown(player,
                                   (void**)&pUnk);
    g_return_val_if_fail(result != FALSE, NULL);

    retVal = pUnk->QueryInterface(IID_IHXPlugin2Handler,
                                  (void**)&pPlugin2Handler);
    g_return_val_if_fail(pPlugin2Handler && SUCCEEDED(retVal), NULL);

    retVal = pUnk->QueryInterface(IID_IHXPluginEnumerator,
                                  (void**)&pPluginEnumerator);
    g_return_val_if_fail(pPluginEnumerator && SUCCEEDED(retVal), NULL);

    /* Build a list of datatypes */
    UINT32 nFileFormatPlugins = 0;
    UINT32 nMimeMgrPlugins = 0;
    UINT32 nPlugins;
    UINT32 i;
    
    /* Get supported mime types */
    nPlugins = pPluginEnumerator->GetNumOfPlugins();

    for(i = 0; i < nPlugins; i++)
    {        
        pMimeAssocMgr = NULL;
        pFileFormat = NULL;

        retVal = pPluginEnumerator->GetPlugin(i, pUnk);

        if(SUCCEEDED(retVal))
        {
            retVal = pUnk->QueryInterface(IID_IHXMimeAssocManager,
                                          (void**)&pMimeAssocMgr);
        }

        if(SUCCEEDED(retVal))
        {

            retVal = pUnk->QueryInterface(IID_IHXFileFormatObject,
                                          (void**)&pFileFormat);
        }

        if(SUCCEEDED(retVal))
        {
            info->mime_association_managers_list =
                g_list_append(info->mime_association_managers_list,
                              pMimeAssocMgr);

            info->file_formats_list = g_list_append(info->file_formats_list,
                                                    pFileFormat);
        }
    }
    
    /* Get mime type association plugins */
    nMimeMgrPlugins = g_list_length(info->mime_association_managers_list);
    nFileFormatPlugins = g_list_length(info->file_formats_list);
            
    if(nMimeMgrPlugins == 0)
    {
        /* Switch tree view to a "no mime plugins found" tab & return. */
        gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 1);
        hxplay_mime_types_pane_destroy(info);
        info = NULL;
    }
    else
    {
        gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
        populate_mime_types_tree_view(info);        
    }

    HX_RELEASE(pPlugin2Handler);
    HX_RELEASE(pPluginEnumerator);

    return info;
}

