/*
 * updater.h by Matthias Braun <matze@braunis.de>
 *
 * Copyright (C) 2002 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) 
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation (version 2 of the License)
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
#ifndef __UPDATER_H__
#define __UPDATER_H__

#include <csutil/array.h>
#include <csutil/csstring.h>
#include <iutil/document.h>
#include <csutil/thread.h>
#include <csutil/stringarray.h>

#include "change.h"
struct iObjectRegistry;

namespace updater
{

class ChangeList;
class Registry;
class Module;
class RegistryFile;
class Config;
class Downloader;

/** The main updater class is the highlevel wrapper around downloader and
 * registry handling.
 */
class Updater: public csRunnable, csRefCount
{
public:
    Updater ();
    virtual ~Updater ();

    bool Initialize(iObjectRegistry* object_reg );
    
    void RefreshModules();

    void StartUpdate();
    
    /// Load Cached registry from disk (filename is a vfs path)
    bool LoadRegistryCache (const char* filename);
    /// Cache registry on disk (filename is a vfs path)
    void SaveRegistryCache (const char* filename);
    /// Download new registry file from url
    bool DownloadRegistry ();

    /** Compares the files on the disk with the registries and creates a
     * changelist for the differences
     */
    bool CheckUpdates(ChangeList& changelist);

    /** Commit a series of updates */
    bool PerformUpdates (ChangeList& changelist);

    iObjectRegistry* GetObjectRegistry() {return objreg;}

    bool CopyFile(csString name1, csString name2, bool vfsPath = false, bool silent = false);
    void CopyDirectory(const char* vfsPath,const char* to);

    int CreateRegistry (iObjectRegistry* objreg, const char* path);

    /// Necessary CS definition and stub function
    virtual void IncRef ()
    {csRefCount::IncRef();}
    /// Necessary CS definition and stub function
    virtual void DecRef ()
    {csRefCount::DecRef();}

    virtual int GetRefCount() { return csRefCount::GetRefCount(); }

    void CopyZipDir( csString dir, csString directory );

    /// Stop updating and cleanup
    void EndUpdate();

    void Die();

    bool CheckNewUpdater();
    bool UpdateUpdater();

    void CleanUp();

    Config* GetConfig() { return config; }
    Downloader* GetDownloader() { return downloader; }

    void Compare();

    bool IsRunning();

    void CreateToDoList(ChangeList* changelist,int mirror);

    void RemoveDuplicatedZips(ChangeList* changelist);

    struct ZipPercent
    {
        csString zip;
        size_t bytes;
        size_t update;
        RegistryFile* oneFile;
        csString module;
    };

    void DoZipPercentCheck(ChangeList* changelist);
    size_t GetBytesInZipDir(const char* dir);
    size_t GetBytesInZip(const char* zip);

    Registry* GetRepository() {return newregistry;}

    csPtr<Registry> LoadRepositoryZip(const char* zip);

    unsigned int GetVersionFromFile(const char* file);
    
    bool ValidateVersionInfo(const char* info);
    
    csString CreateVersionInfo(Registry* reg);
    
    void MoveFile(const char* from, const char* to);

protected:
    void Run();

private:

    bool DoUpdate (iObjectRegistry* objreg);

    bool CheckUpdatesFileRemoved (ChangeList& changelist,
                  Module* module,
                  Module* old_module,
                  RegistryFile* file);
    
    iObjectRegistry* objreg;

    csRef<Registry> registrycache;
    csRef<Registry> newregistry;

    /// represent the list of modules we're interested in
    csArray<csString> modulechoice;
        
    Config* config;
    Downloader* downloader;
    char* configfilename;
    csRef<iDocument> configdoc;
    csString prevZip; // Define here so we can get the path outside the loop

    csRef<iVFS> vfs;

    csRef<csThread> thread;
    bool running;
    bool cleanupNeeded;

    //List of failed files
    csArray<csString> failed;
    
    void Size( size_t size, float& fsize, csString& unit );
    bool IsSpecialZip( csString&  zip );
    bool HandleSpecialZipUpdate( Change& change );
    
    void UpdateRemoveFile( Change& change );
    void UpdateZip( Change& change );
    void UpdateCreateFile( Change& change );
    
    csStringArray specialsDownloaded;
    
    /// Returns true if the server has a newer registry to download
    bool CheckRegistryVersion();
};

} // end of namespace updater

#endif

