function synchronise_folder($folder_id)
{
    global $site;
    $folder_id = (int) $folder_id;
    $objekt = new Objekt(array('objekt_id' => $folder_id));
    if ($objekt->objekt_id == $folder_id && $objekt->all['tyyp_id'] == 22) {
        $objekt->load_sisu();
        $folder_path = preg_replace('#/$#', '', $site->absolute_path) . $objekt->all['relative_path'];
        // get folder & file count in this from database
        $sql = 'select count(objekt_id) from objekt_objekt where parent_id = ' . $folder_id;
        $result = new SQL($sql);
        $db_object_count = $result->fetchsingle();
        // check if folder & file count from db matches count in file system
        $fs_object_count = 0;
        if ($dir = opendir($folder_path)) {
            while (false !== ($file = readdir($dir))) {
                if (strpos($file, '.') !== 0) {
                    $fs_object_count++;
                    // break counting if there are more files, syncro is needed
                    if ($fs_object_count > $db_object_count) {
                        break;
                    }
                }
            }
            closedir($dir);
        } else {
            // not a folder ... TODO
        }
        //if the fs and db object count do not match syncronise folder contents
        if ($fs_object_count != $db_object_count) {
            // collect files and folder from fs
            $fs_files = array();
            $fs_folders = array();
            $dir = opendir($folder_path);
            while (false !== ($file = readdir($dir))) {
                if (strpos($file, '.') !== 0) {
                    if (is_dir($folder_path . '/' . $file)) {
                        $fs_folders[$file] = $file;
                    } else {
                        $fs_files[$file] = array('filename' => $file, 'size' => @filesize($folder_path . '/' . $file), 'mimetype' => get_file_mime_content_type($folder_path . '/' . $file));
                    }
                }
            }
            closedir($dir);
            // files first
            $sql = 'select obj_file.objekt_id, filename, mimetype, size from obj_file left join objekt_objekt on obj_file.objekt_id = objekt_objekt.objekt_id where parent_id = ' . $folder_id;
            $result = new SQL($sql);
            $files_to_delete = array();
            while ($row = $result->fetch('ASSOC')) {
                // mark files not found in fs for deletion
                if (!$fs_files[$row['filename']]) {
                    $files_to_delete[] = $row['objekt_id'];
                } else {
                    // update file size, mimetype if needed
                    if ($fs_files[$row['filename']]['size'] != $row['size'] || $fs_files[$row['filename']]['mimetype'] != $row['mimetype']) {
                        $sql = $site->db->prepare("update obj_file set size = ?, mimetype = ? where objekt_id = ?", $fs_files[$row['filename']]['size'], $fs_files[$row['filename']]['mimetype'], $row['objekt_id']);
                        new SQL($sql);
                        // set
                        $sql = $site->db->prepare("update objekt set changed_time = now(), changed_user_id = ?, changed_user_name = ? where objekt_id = ?", $site->user->user_id, $site->user->name, $row['objekt_id']);
                        new SQL($sql);
                    }
                    // check for thumbnail
                    if (!file_exists($folder_path . '/.thumbnails/' . $row['filename'])) {
                        // create thumbnail
                        create_file_thumbnail($folder_path . '/' . $row['filename']);
                    }
                    // remove from fs object array
                    unset($fs_files[$row['filename']]);
                }
            }
            // delete files not in fs TODO: catch errors from file delete
            delete_files($files_to_delete);
            // left over files are new, create them
            foreach ($fs_files as $filename => $file) {
                $safe_filename = safe_filename2($filename);
                if ($safe_filename != $filename) {
                    if (rename($folder_path . '/' . $filename, $folder_path . '/' . $safe_filename)) {
                    } else {
                        // log unable to rename, skip
                        new Log(array('action' => 'create', 'component' => 'Files', 'type' => 'ERROR', 'message' => "Could not rename '" . $objekt->all['relative_path'] . '/' . $filename . "' to '" . $objekt->all['relative_path'] . '/' . $safe_filename . "', file system error."));
                        continue;
                    }
                }
                // objekt
                insert_new_file_object($objekt, $filename, $file['size'], $file['mimetype']);
                // create thumbnail
                create_file_thumbnail($folder_path . '/' . $safe_filename);
            }
            // folders next
            $sql = 'select obj_folder.objekt_id, relative_path from obj_folder left join objekt_objekt on obj_folder.objekt_id = objekt_objekt.objekt_id where parent_id = ' . $folder_id;
            $result = new SQL($sql);
            $folders_to_delete = array();
            while ($row = $result->fetch('ASSOC')) {
                $folder_name = str_replace($objekt->all['relative_path'] . '/', '', $row['relative_path']);
                // mark folders not found in fs for deletion
                if (!$fs_folders[$folder_name]) {
                    $folders_to_delete[] = $row['objekt_id'];
                } else {
                    // remove from fs object array
                    unset($fs_folders[$folder_name]);
                }
            }
            // delete folders present in db but not present in fs
            foreach ($folders_to_delete as $folder_id) {
                // TODO: error catching from folder deleting
                delete_folder($folder_id);
            }
            // create new folders
            foreach ($fs_folders as $folder_name) {
                create_folder($folder_name, $objekt->objekt_id);
            }
            new Log(array('action' => 'sync', 'component' => 'Files', 'objekt_id' => $objekt->objekt_id, 'message' => "Folder '" . $objekt->all['relative_path'] . "' (ID = " . $objekt->objekt_id . ") synchronised."));
            // recurse?
            return true;
        } else {
            // nothing to syncro
            return true;
        }
    } else {
        return 'no_such_folder_object';
    }
}
function salvesta_objekt()
{
    global $site;
    global $objekt;
    global $class_path;
    if ($objekt->objekt_id) {
        if ($objekt->on_sisu_olemas) {
            # -------------------------------
            # Objekti uuendamine andmebaasis
            # -------------------------------
            $parent_folder = new Objekt(array('objekt_id' => $objekt->parent_id, 'on_sisu' => 1));
            $fileupload = $_FILES['fileupload'];
            if ($fileupload['name'] && $parent_folder->all['relative_path']) {
                $fileupload['name'] = safe_filename2($fileupload['name']);
                $upload_path = preg_replace('#/$#', '', $site->absolute_path) . $parent_folder->all['relative_path'];
                $upload = upload_file_to_folder($fileupload, $upload_path);
                if ($upload === true) {
                    create_file_thumbnail($upload_path . '/' . $fileupload['name']);
                    $pealkiri = $site->fdat['pealkiri'] ? $site->fdat['pealkiri'] : $fileupload['name'];
                    $mimetype = get_file_mime_content_type($upload_path . '/' . $fileupload['name']);
                    $pathinfo = pathinfo($upload_path . '/' . $fileupload['name']);
                    ############ 1) update record in object content table:
                    $sql = $site->db->prepare("update obj_file set relative_path = ?, filename = ?, mimetype = ?, size = ? where objekt_id = ?;", $parent_folder->all['relative_path'] . '/' . $fileupload['name'], $pathinfo['basename'], $mimetype, filesize($upload_path . '/' . $fileupload['name']), $objekt->objekt_id);
                    $sth = new SQL($sql);
                    //if($site->fdat['dir']) refresh_gallery_images($objekt, $site->fdat['dir']);
                }
                //if fullpath
            }
            //if file size
            ############ 1) create always record in object content table:
            $sql = $site->db->prepare("UPDATE obj_file SET profile_id=? WHERE objekt_id=?", $site->fdat['profile_id'], $objekt->objekt_id);
            $sth = new SQL($sql);
            $site->debug->msg($sth->debug->get_msgs());
            if ($site->fdat['in_wysiwyg'] == 1) {
                $objekt->all['in_wysiwyg_filename'] = $pathinfo['basename'];
                // very ugly workaround for bug #2269
                //printr($objekt->all['in_wysiwyg_filename']);
            }
        } else {
            # -------------------------------
            # Objekti loomine andmebaasis
            # -------------------------------
            /*
             * Upload file data and make thumbnail
             */
            /*
            # old usage of "dir" - when files where not content objects as should,
            # find "dir" value from "parent_id" (parent_id overrules any "dir" value):
            if($site->fdat['parent_id']){
            	$sql = $site->db->prepare("SELECT * FROM obj_folder  WHERE objekt_id = ?", $site->fdat['parent_id']);
            	$sth = new SQL($sql);
            	$parent_folder = $sth->fetch();
            }
            */
            if ($objekt->parent_id) {
                $parent_folder = new Objekt(array('objekt_id' => $objekt->parent_id, 'on_sisu' => 1));
            } elseif ($site->fdat['parent_id']) {
                $parent_folder = new Objekt(array('objekt_id' => $site->fdat['parent_id'], 'on_sisu' => 1));
            } elseif ($site->fdat['dir']) {
                $sql = $site->db->prepare('select objekt_id from obj_folder where relative_path = ?', '/' . $site->fdat['dir']);
                $result = new SQL($sql);
                $parent_folder = new Objekt(array('objekt_id' => $result->fetchsingle(), 'on_sisu' => 1));
            } else {
                //screwed, dont know where to put the object
                exit;
            }
            $site->fdat['dir'] = preg_replace('#^/#', '', $parent_folder->all['relative_path']);
            $fileupload = $_FILES['fileupload'];
            if ($fileupload['name'] && $parent_folder->all['relative_path']) {
                $fileupload['name'] = safe_filename2($fileupload['name']);
                $upload_path = preg_replace('#/$#', '', $site->absolute_path) . $parent_folder->all['relative_path'];
                $upload = upload_file_to_folder($fileupload, $upload_path);
                $fullpath = $upload_path . '/' . $fileupload['name'];
                if ($upload === true) {
                    create_file_thumbnail($fullpath);
                    $pealkiri = $site->fdat['pealkiri'] ? $site->fdat['pealkiri'] : $fileupload['name'];
                    $mimetype = get_file_mime_content_type($fullpath);
                    $pathinfo = pathinfo($fullpath);
                    ############ 1) create always record in object content table:
                    $sql = $site->db->prepare("INSERT INTO obj_file (objekt_id, relative_path, filename, mimetype, size, profile_id) VALUES (?,?,?,?,?,?)", $objekt->objekt_id, $parent_folder->all['relative_path'] . '/' . $pathinfo['basename'], $pathinfo['basename'], $mimetype, filesize($fullpath), $site->fdat['profile_id']);
                    #print $sql."<hr>";
                    $sth = new SQL($sql);
                    if ($site->fdat['in_wysiwyg'] == 1) {
                        $objekt->all['in_wysiwyg_filename'] = $pathinfo['basename'];
                        // very ugly workaround for bug #2269
                    }
                    if ($site->fdat['dir']) {
                        refresh_gallery_images($objekt, $site->fdat['dir']);
                    }
                }
                //if fullpath
            }
            //if file size
        }
        //if update or insert
    } else {
        $site->debug->msg("sisu pole salvestatud kuna objekt_id puudub");
    }
}